mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Update all dependencies
This commit is contained in:
@@ -82,7 +82,7 @@ dependencies {
|
||||
// Utility
|
||||
implementation(libs.dateTime)
|
||||
implementation(libs.immutableCollections)
|
||||
implementation(libs.kds)
|
||||
implementation(libs.korge.foundation)
|
||||
|
||||
// Localization
|
||||
implementation(libs.moko.core)
|
||||
@@ -90,7 +90,7 @@ dependencies {
|
||||
|
||||
// Testing
|
||||
testImplementation(kotlin("test-junit"))
|
||||
testImplementation(libs.compose.ui.test.junit4)
|
||||
//testImplementation(libs.compose.ui.test.junit4)
|
||||
testImplementation(libs.coroutines.test)
|
||||
}
|
||||
|
||||
|
||||
@@ -50,14 +50,16 @@ subprojects {
|
||||
if (name.contains("android", true)) {
|
||||
jvmTarget = Config.androidJvmTarget.toString()
|
||||
}
|
||||
freeCompilerArgs += listOf("-Xexpect-actual-classes")
|
||||
|
||||
if (project.hasProperty("generateComposeCompilerMetrics")) {
|
||||
freeCompilerArgs = freeCompilerArgs + listOf(
|
||||
"-P",
|
||||
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
|
||||
project.buildDir.absolutePath + "/compose_metrics",
|
||||
project.layout.buildDirectory.dir("compose_metrics").get().asFile.absolutePath,
|
||||
"-P",
|
||||
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
|
||||
project.buildDir.absolutePath + "/compose_metrics"
|
||||
project.layout.buildDirectory.dir("compose_metrics").get().asFile.absolutePath
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -72,7 +74,7 @@ subprojects {
|
||||
}
|
||||
plugins.withType<com.android.build.gradle.BasePlugin> {
|
||||
configure<com.android.build.gradle.BaseExtension> {
|
||||
compileSdkVersion(33)
|
||||
compileSdkVersion(34)
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
targetSdk = 31
|
||||
@@ -126,9 +128,8 @@ subprojects {
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withType<de.jensklingenberg.ktorfit.gradle.KtorfitGradleSubPlugin> {
|
||||
plugins.withType<de.jensklingenberg.ktorfit.gradle.KtorfitGradlePlugin> {
|
||||
configure<de.jensklingenberg.ktorfit.gradle.KtorfitGradleConfiguration> {
|
||||
version = libs.versions.ktorfit.get()
|
||||
logging = project.hasProperty("debugApp")
|
||||
}
|
||||
}
|
||||
@@ -140,7 +141,7 @@ subprojects {
|
||||
}
|
||||
plugins.withType<ComposePlugin> {
|
||||
configure<ComposeExtension> {
|
||||
kotlinCompilerPlugin.set(libs.versions.composeCompiler.get())
|
||||
// kotlinCompilerPlugin.set(libs.versions.composeCompiler.get())
|
||||
}
|
||||
}
|
||||
afterEvaluate {
|
||||
|
||||
@@ -12,5 +12,5 @@ dependencies {
|
||||
implementation(gradleKotlinDsl())
|
||||
implementation(gradleApi())
|
||||
implementation(localGroovy())
|
||||
implementation("de.undercouch:gradle-download-task:5.3.0")
|
||||
implementation(libs.gradle.download.task)
|
||||
}
|
||||
|
||||
@@ -1,2 +1,11 @@
|
||||
|
||||
rootProject.name = "buildSrc"
|
||||
|
||||
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ plugins {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
androidTarget {
|
||||
compilations {
|
||||
all {
|
||||
kotlinOptions.jvmTarget = Config.androidJvmTarget.toString()
|
||||
@@ -28,6 +28,21 @@ kotlin {
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
applyHierarchyTemplate {
|
||||
common {
|
||||
group("jvm") {
|
||||
withAndroidTarget()
|
||||
withJvm()
|
||||
}
|
||||
group("ios") {
|
||||
withIosX64()
|
||||
withIosArm64()
|
||||
withIosSimulatorArm64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings {
|
||||
@@ -53,7 +68,7 @@ kotlin {
|
||||
api(libs.multiplatformSettings.coroutines)
|
||||
api(libs.multiplatformSettings.serialization)
|
||||
api(libs.dateTime)
|
||||
api(libs.kds)
|
||||
api(libs.korge.foundation)
|
||||
api(compose("org.jetbrains.compose.ui:ui-text"))
|
||||
}
|
||||
}
|
||||
@@ -64,53 +79,28 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
}
|
||||
val jvmTest by creating {
|
||||
dependsOn(commonTest)
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
dependencies {
|
||||
api(libs.appDirs)
|
||||
}
|
||||
}
|
||||
val desktopTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
dependencies {
|
||||
api(libs.compose.ui.text)
|
||||
}
|
||||
}
|
||||
val androidUnitTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val iosMain by creating {
|
||||
dependsOn(commonMain)
|
||||
}
|
||||
val iosTest by creating {
|
||||
dependsOn(commonTest)
|
||||
}
|
||||
|
||||
listOf(
|
||||
"iosX64",
|
||||
"iosArm64",
|
||||
"iosSimulatorArm64",
|
||||
).forEach {
|
||||
getByName(it + "Main").dependsOn(iosMain)
|
||||
getByName(it + "Test").dependsOn(iosTest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ plugins {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
androidTarget {
|
||||
compilations {
|
||||
all {
|
||||
kotlinOptions.jvmTarget = Config.androidJvmTarget.toString()
|
||||
@@ -28,6 +28,21 @@ kotlin {
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
applyHierarchyTemplate {
|
||||
common {
|
||||
group("jvm") {
|
||||
withAndroidTarget()
|
||||
withJvm()
|
||||
}
|
||||
group("ios") {
|
||||
withIosX64()
|
||||
withIosArm64()
|
||||
withIosSimulatorArm64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings {
|
||||
@@ -58,47 +73,30 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
}
|
||||
val jvmTest by creating {
|
||||
dependsOn(commonTest)
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
}
|
||||
val desktopTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
}
|
||||
val androidUnitTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val iosMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val iosMain by getting {
|
||||
}
|
||||
val iosTest by creating {
|
||||
dependsOn(commonTest)
|
||||
}
|
||||
|
||||
listOf(
|
||||
"iosX64",
|
||||
"iosArm64",
|
||||
"iosSimulatorArm64",
|
||||
).forEach {
|
||||
getByName(it + "Main").dependsOn(iosMain)
|
||||
getByName(it + "Test").dependsOn(iosTest)
|
||||
val iosTest by getting {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ dependencies {
|
||||
// Utility
|
||||
implementation(libs.dateTime)
|
||||
implementation(libs.immutableCollections)
|
||||
implementation(libs.kds)
|
||||
implementation(libs.korge.foundation)
|
||||
|
||||
// Localization
|
||||
implementation(libs.moko.core)
|
||||
|
||||
@@ -11,7 +11,7 @@ plugins {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
androidTarget {
|
||||
compilations {
|
||||
all {
|
||||
kotlinOptions.jvmTarget = Config.androidJvmTarget.toString()
|
||||
@@ -29,6 +29,21 @@ kotlin {
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
applyHierarchyTemplate {
|
||||
common {
|
||||
group("jvm") {
|
||||
withAndroidTarget()
|
||||
withJvm()
|
||||
}
|
||||
group("ios") {
|
||||
withIosX64()
|
||||
withIosArm64()
|
||||
withIosSimulatorArm64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings {
|
||||
@@ -66,51 +81,34 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(libs.ktor.okHttp)
|
||||
}
|
||||
}
|
||||
val jvmTest by creating {
|
||||
dependsOn(commonTest)
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
}
|
||||
val desktopTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
}
|
||||
val androidUnitTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val iosMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val iosMain by getting {
|
||||
dependencies {
|
||||
api(libs.ktor.darwin)
|
||||
}
|
||||
}
|
||||
val iosTest by creating {
|
||||
dependsOn(commonTest)
|
||||
}
|
||||
|
||||
listOf(
|
||||
"iosX64",
|
||||
"iosArm64",
|
||||
"iosSimulatorArm64",
|
||||
).forEach {
|
||||
getByName(it + "Main").dependsOn(iosMain)
|
||||
getByName(it + "Test").dependsOn(iosTest)
|
||||
val iosTest by getting {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import io.ktor.client.plugins.auth.providers.DigestAuthCredentials
|
||||
import io.ktor.client.plugins.auth.providers.basic
|
||||
import io.ktor.client.plugins.auth.providers.digest
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.plugins.defaultRequest
|
||||
import io.ktor.client.plugins.logging.LogLevel
|
||||
import io.ktor.client.plugins.logging.Logger
|
||||
import io.ktor.client.plugins.logging.Logging
|
||||
@@ -49,6 +50,10 @@ fun httpClient(
|
||||
|
||||
expectSuccess = true
|
||||
|
||||
defaultRequest {
|
||||
url(serverPreferences.serverUrl().get().toString())
|
||||
}
|
||||
|
||||
engine {
|
||||
proxy = when (serverPreferences.proxy().get()) {
|
||||
Proxy.NO_PROXY -> null
|
||||
|
||||
@@ -4,6 +4,5 @@ android.enableJetifier=false
|
||||
android.useAndroidX=true
|
||||
kotlin.mpp.stability.nowarn=true
|
||||
kotlin.native.ignoreDisabledTargets=true
|
||||
kotlin.native.cacheKind=none
|
||||
org.jetbrains.compose.experimental.uikit.enabled=true
|
||||
kotlin.mpp.androidSourceSetLayoutVersion=2
|
||||
|
||||
@@ -1,82 +1,76 @@
|
||||
[versions]
|
||||
# Kotlin
|
||||
kotlin = "1.8.22"
|
||||
coroutines = "1.7.2"
|
||||
kotlin = "1.9.21"
|
||||
coroutines = "1.7.3"
|
||||
|
||||
# Serialization
|
||||
json = "1.5.1"
|
||||
json = "1.6.2"
|
||||
|
||||
# Compose
|
||||
composeGradle = "1.4.1"
|
||||
composeCompiler = "1.4.8"
|
||||
composeAndroidRuntime = "1.4.3"
|
||||
composeAndroidFoundation = "1.4.3"
|
||||
composeAndroidUI = "1.4.3"
|
||||
composeAndroidAnimation = "1.4.3"
|
||||
composeAndroidMaterial = "1.4.3"
|
||||
composeGradle = "1.5.11"
|
||||
|
||||
# Compose Libraries
|
||||
voyager = "1.0.0-rc06"
|
||||
voyager = "1.0.0-rc10"
|
||||
accompanist = "0.30.1"
|
||||
googleAccompanist = "0.30.1"
|
||||
imageloader = "1.5.3"
|
||||
materialDialogs = "0.9.3"
|
||||
imageloader = "1.7.1"
|
||||
materialDialogs = "0.9.4"
|
||||
|
||||
# Android
|
||||
androidGradle = "8.0.2"
|
||||
core = "1.9.0"
|
||||
appCompat = "1.7.0-alpha02"
|
||||
activityCompose = "1.7.2"
|
||||
work = "2.8.1"
|
||||
androidGradle = "8.1.4"
|
||||
core = "1.12.0"
|
||||
appCompat = "1.7.0-alpha03"
|
||||
activityCompose = "1.8.1"
|
||||
work = "2.9.0"
|
||||
|
||||
# Android Lifecycle
|
||||
lifecycle = "2.6.1"
|
||||
lifecycle = "2.6.2"
|
||||
|
||||
# Swing
|
||||
darklaf = "3.0.2"
|
||||
|
||||
# Ksp
|
||||
ksp = "1.8.22-1.0.11"
|
||||
ksp = "1.9.21-1.0.15"
|
||||
|
||||
# Dependency Injection
|
||||
kotlinInject = "0.6.1"
|
||||
kotlinInject = "0.6.3"
|
||||
|
||||
# Network
|
||||
ktor = "2.3.2"
|
||||
ktorfit = "1.4.2"
|
||||
ktorfitCompiler = "1.0.0"
|
||||
ktor = "2.3.6"
|
||||
ktorfit = "1.10.2"
|
||||
|
||||
# Logging
|
||||
slf4j = "2.0.7"
|
||||
log4j = "2.20.0"
|
||||
slf4j = "2.0.9"
|
||||
log4j = "2.22.0"
|
||||
kmlogging = "1.3.0"
|
||||
|
||||
# Storage
|
||||
okio = "3.3.0"
|
||||
okio = "3.6.0"
|
||||
appDirs = "1.2.1"
|
||||
|
||||
# Preferences
|
||||
multiplatformSettings = "1.0.0-alpha01"
|
||||
|
||||
# Utility
|
||||
desugarJdkLibs = "2.0.3"
|
||||
aboutLibraries = "10.8.0"
|
||||
dateTime = "0.4.0"
|
||||
immutableCollections = "0.3.5"
|
||||
kds = "4.0.7"
|
||||
desugarJdkLibs = "2.0.4"
|
||||
aboutLibraries = "10.9.2"
|
||||
dateTime = "0.5.0"
|
||||
immutableCollections = "0.3.6"
|
||||
korge = "5.1.0"
|
||||
gradleDownloadTask = "5.4.0"
|
||||
|
||||
# Localization
|
||||
moko = "0.23.0"
|
||||
|
||||
# BuildConfigs
|
||||
buildconfig = "4.1.1"
|
||||
buildkonfig = "0.13.3"
|
||||
buildconfig = "4.2.0"
|
||||
buildkonfig = "0.15.1"
|
||||
|
||||
# Linter
|
||||
kotlinter = "3.15.0"
|
||||
kotlinter = "4.1.0"
|
||||
|
||||
# Version updates
|
||||
versions = "0.47.0"
|
||||
versions = "0.50.0"
|
||||
|
||||
# Optimizer
|
||||
proguard = "7.3.2"
|
||||
@@ -92,16 +86,6 @@ coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", ve
|
||||
serialization-json-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "json" }
|
||||
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "json" }
|
||||
|
||||
# Compose
|
||||
compose-animation = { module = "androidx.compose.animation:animation", version.ref = "composeAndroidAnimation" }
|
||||
compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "composeAndroidFoundation" }
|
||||
compose-runtime = { module = "androidx.compose.runtime:runtime", version.ref = "composeAndroidRuntime" }
|
||||
compose-ui-core = { module = "androidx.compose.ui:ui", version.ref = "composeAndroidUI" }
|
||||
compose-ui-util = { module = "androidx.compose.ui:ui-util", version.ref = "composeAndroidUI" }
|
||||
compose-ui-text = { module = "androidx.compose.ui:ui-text", version.ref = "composeAndroidUI" }
|
||||
compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version.ref = "composeAndroidUI" }
|
||||
compose-material-core = { module = "androidx.compose.material:material", version.ref = "composeAndroidMaterial" }
|
||||
compose-material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "composeAndroidMaterial" }
|
||||
# Compose UI
|
||||
voyager-core = { module = "cafe.adriel.voyager:voyager-core", version.ref = "voyager" }
|
||||
voyager-navigation = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
|
||||
@@ -168,7 +152,7 @@ aboutLibraries-core = { module = "com.mikepenz:aboutlibraries-core", version.ref
|
||||
aboutLibraries-ui = { module = "com.mikepenz:aboutlibraries-compose", version.ref = "aboutLibraries" }
|
||||
dateTime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "dateTime" }
|
||||
immutableCollections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "immutableCollections" }
|
||||
kds = { module = "com.soywiz.korlibs.kds:kds", version.ref = "kds" }
|
||||
korge-foundation = { module = "com.soywiz.korge:korge-foundation", version.ref = "korge" }
|
||||
|
||||
# Localization
|
||||
moko-core = { module = "dev.icerock.moko:resources", version.ref = "moko" }
|
||||
@@ -177,6 +161,9 @@ moko-compose = { module = "dev.icerock.moko:resources-compose", version.ref = "m
|
||||
# Optimizer
|
||||
proguard = { module = "com.guardsquare:proguard-gradle", version.ref = "proguard" }
|
||||
|
||||
# Gradle
|
||||
gradle-download-task = { module = "de.undercouch:gradle-download-task", version.ref = "gradleDownloadTask" }
|
||||
|
||||
[plugins]
|
||||
# Kotlin
|
||||
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||
@@ -195,7 +182,7 @@ compose = { id = "org.jetbrains.compose", version.ref = "composeGradle" }
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
|
||||
# Network
|
||||
ktorfit = { id = "de.jensklingenberg.ktorfit", version.ref = "ktorfitCompiler" }
|
||||
ktorfit = { id = "de.jensklingenberg.ktorfit", version.ref = "ktorfit" }
|
||||
|
||||
# Localization
|
||||
moko-gradle = { id = "dev.icerock.mobile.multiplatform-resources", version.ref = "moko" }
|
||||
@@ -215,11 +202,4 @@ aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "abo
|
||||
|
||||
[bundles]
|
||||
compose-android = [
|
||||
"compose-animation",
|
||||
"compose-foundation",
|
||||
"compose-runtime",
|
||||
"compose-ui-core",
|
||||
"compose-ui-util",
|
||||
"compose-material-core",
|
||||
"compose-material-icons"
|
||||
]
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
5
gradlew
vendored
5
gradlew
vendored
@@ -130,11 +130,14 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
|
||||
@@ -6,7 +6,7 @@ plugins {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
androidTarget {
|
||||
compilations {
|
||||
all {
|
||||
kotlinOptions.jvmTarget = Config.androidJvmTarget.toString()
|
||||
@@ -31,6 +31,8 @@ kotlin {
|
||||
iosArm64(configure = configuration)
|
||||
iosSimulatorArm64(configure = configuration)
|
||||
|
||||
applyDefaultHierarchyTemplate()
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
@@ -44,6 +46,14 @@ kotlin {
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
}
|
||||
}
|
||||
|
||||
getByName("desktopMain") {
|
||||
dependsOn(commonMain)
|
||||
}
|
||||
|
||||
getByName("androidMain") {
|
||||
dependsOn(commonMain)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +75,7 @@ android {
|
||||
}
|
||||
|
||||
sourceSets.getByName("main") {
|
||||
assets.srcDir(File(buildDir, "generated/moko/androidMain/assets"))
|
||||
res.srcDir(File(buildDir, "generated/moko/androidMain/res"))
|
||||
assets.srcDir(File(layout.buildDirectory.asFile.get(), "generated/moko/androidMain/assets"))
|
||||
res.srcDir(File(layout.buildDirectory.asFile.get(), "generated/moko/androidMain/res"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import org.jetbrains.compose.compose
|
||||
import org.jetbrains.compose.experimental.uikit.tasks.ExperimentalPackComposeApplicationForXCodeTask
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
|
||||
import java.io.File
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
|
||||
@Suppress("DSL_SCOPE_VIOLATION")
|
||||
plugins {
|
||||
@@ -17,28 +13,28 @@ plugins {
|
||||
|
||||
kotlin {
|
||||
val configuration: KotlinNativeTarget.() -> Unit = {
|
||||
binaries {
|
||||
executable {
|
||||
entryPoint = "ca.gosyer.jui.ios.main"
|
||||
freeCompilerArgs = freeCompilerArgs + listOf(
|
||||
"-linker-option", "-framework", "-linker-option", "Metal",
|
||||
"-linker-option", "-framework", "-linker-option", "CoreText",
|
||||
"-linker-option", "-framework", "-linker-option", "CoreGraphics"
|
||||
)
|
||||
// TODO: the current compose binary surprises LLVM, so disable checks for now.
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xdisable-phases=VerifyBitcode"
|
||||
}
|
||||
binaries.framework {
|
||||
baseName = "ios"
|
||||
isStatic = true
|
||||
}
|
||||
}
|
||||
iosX64("uikitX64", configuration)
|
||||
iosArm64("uikitArm64", configuration)
|
||||
iosSimulatorArm64("uikitSimulatorArm64", configuration)
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
applyHierarchyTemplate {
|
||||
common {
|
||||
group("uikit") {
|
||||
withIosX64()
|
||||
withIosArm64()
|
||||
withIosSimulatorArm64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting
|
||||
val commonTest by getting
|
||||
val uikitMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val uikitMain by getting {
|
||||
dependencies {
|
||||
implementation(projects.core)
|
||||
implementation(projects.i18n)
|
||||
@@ -100,7 +96,7 @@ kotlin {
|
||||
// Utility
|
||||
implementation(libs.dateTime)
|
||||
implementation(libs.immutableCollections)
|
||||
implementation(libs.kds)
|
||||
implementation(libs.korge.foundation)
|
||||
|
||||
// Localization
|
||||
implementation(libs.moko.core)
|
||||
@@ -112,30 +108,7 @@ kotlin {
|
||||
testImplementation(libs.coroutines.test)*/
|
||||
}
|
||||
}
|
||||
val uikitTest by creating {
|
||||
dependsOn(commonTest)
|
||||
}
|
||||
|
||||
listOf(
|
||||
"uikitX64",
|
||||
"uikitArm64",
|
||||
"uikitSimulatorArm64",
|
||||
).forEach {
|
||||
getByName(it + "Main").dependsOn(uikitMain)
|
||||
getByName(it + "Test").dependsOn(uikitTest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compose.experimental {
|
||||
uikit.application {
|
||||
bundleIdPrefix = "ca.gosyer.jui.app.ios"
|
||||
projectName = "Tachidesk-JUI"
|
||||
// ./gradlew :app:ios:iosDeployIPhone13Debug
|
||||
deployConfigurations {
|
||||
simulator("IPhone13") {
|
||||
device = org.jetbrains.compose.experimental.dsl.IOSDevices.IPHONE_13
|
||||
}
|
||||
val uikitTest by getting {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,92 +124,6 @@ dependencies {
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
|
||||
binaries.all {
|
||||
// TODO: the current compose binary surprises LLVM, so disable checks for now.
|
||||
freeCompilerArgs = freeCompilerArgs + "-Xdisable-phases=VerifyBitcode"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildkonfig {
|
||||
packageName = "ca.gosyer.jui.ios.build"
|
||||
}
|
||||
|
||||
// todo: Remove when resolved: https://github.com/icerockdev/moko-resources/issues/372
|
||||
// copy .bundle from all .klib to .kexe
|
||||
tasks.withType<KotlinNativeLink>()
|
||||
.configureEach {
|
||||
val linkTask: KotlinNativeLink = this
|
||||
val outputDir: File = this.outputFile.get().parentFile
|
||||
|
||||
@Suppress("ObjectLiteralToLambda") // lambda broke up-to-date
|
||||
val action = object : Action<Task> {
|
||||
override fun execute(t: Task) {
|
||||
(linkTask.libraries + linkTask.sources)
|
||||
.filter { library -> library.extension == "klib" }
|
||||
.filter(File::exists)
|
||||
.forEach { inputFile ->
|
||||
val klibKonan = org.jetbrains.kotlin.konan.file.File(inputFile.path)
|
||||
val klib = org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutImpl(
|
||||
klib = klibKonan,
|
||||
component = "default"
|
||||
)
|
||||
val layout = klib.extractingToTemp
|
||||
|
||||
// extracting bundles
|
||||
layout
|
||||
.resourcesDir
|
||||
.absolutePath
|
||||
.let(::File)
|
||||
.listFiles { file: File -> file.extension == "bundle" }
|
||||
// copying bundles to app
|
||||
?.forEach {
|
||||
logger.info("${it.absolutePath} copying to $outputDir")
|
||||
it.copyRecursively(
|
||||
target = File(outputDir, it.name),
|
||||
overwrite = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doLast(action)
|
||||
}
|
||||
|
||||
// copy .bundle from .kexe to .app
|
||||
tasks.withType<ExperimentalPackComposeApplicationForXCodeTask>()
|
||||
.configureEach {
|
||||
val packTask: ExperimentalPackComposeApplicationForXCodeTask = this
|
||||
|
||||
val kclass = ExperimentalPackComposeApplicationForXCodeTask::class
|
||||
val kotlinBinaryField =
|
||||
kclass.declaredMemberProperties.single { it.name == "kotlinBinary" }
|
||||
val destinationDirField =
|
||||
kclass.declaredMemberProperties.single { it.name == "destinationDir" }
|
||||
val executablePathField =
|
||||
kclass.declaredMemberProperties.single { it.name == "executablePath" }
|
||||
|
||||
@Suppress("ObjectLiteralToLambda") // lambda broke up-to-date
|
||||
val action = object : Action<Task> {
|
||||
override fun execute(t: Task) {
|
||||
val kotlinBinary: RegularFile =
|
||||
(kotlinBinaryField.get(packTask) as RegularFileProperty).get()
|
||||
val destinationDir: Directory =
|
||||
(destinationDirField.get(packTask) as DirectoryProperty).get()
|
||||
val executablePath: String =
|
||||
(executablePathField.get(packTask) as Provider<String>).get()
|
||||
|
||||
val outputDir: File = File(destinationDir.asFile, executablePath).parentFile
|
||||
|
||||
val bundleSearchDir: File = kotlinBinary.asFile.parentFile
|
||||
bundleSearchDir
|
||||
.listFiles { file: File -> file.extension == "bundle" }
|
||||
?.forEach { file ->
|
||||
file.copyRecursively(File(outputDir, file.name), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
doLast(action)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ plugins {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
androidTarget {
|
||||
compilations {
|
||||
all {
|
||||
kotlinOptions.jvmTarget = Config.androidJvmTarget.toString()
|
||||
@@ -29,6 +29,21 @@ kotlin {
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
applyHierarchyTemplate {
|
||||
common {
|
||||
group("jvm") {
|
||||
withAndroidTarget()
|
||||
withJvm()
|
||||
}
|
||||
group("ios") {
|
||||
withIosX64()
|
||||
withIosArm64()
|
||||
withIosSimulatorArm64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings {
|
||||
@@ -78,33 +93,28 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
|
||||
api(compose.desktop.currentOs)
|
||||
}
|
||||
}
|
||||
val jvmTest by creating {
|
||||
dependsOn(commonTest)
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
dependencies {
|
||||
api(libs.coroutines.swing)
|
||||
}
|
||||
}
|
||||
val desktopTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
dependencies {
|
||||
api(libs.bundles.compose.android)
|
||||
api(libs.androidx.core)
|
||||
@@ -114,23 +124,11 @@ kotlin {
|
||||
}
|
||||
}
|
||||
val androidUnitTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val iosMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val iosMain by getting {
|
||||
}
|
||||
val iosTest by creating {
|
||||
dependsOn(commonTest)
|
||||
}
|
||||
|
||||
listOf(
|
||||
"iosX64",
|
||||
"iosArm64",
|
||||
"iosSimulatorArm64",
|
||||
).forEach {
|
||||
getByName(it + "Main").dependsOn(iosMain)
|
||||
getByName(it + "Test").dependsOn(iosTest)
|
||||
val iosTest by getting {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,20 +9,22 @@ package ca.gosyer.jui.ui.base.image
|
||||
import android.os.Build
|
||||
import ca.gosyer.jui.domain.server.Http
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import com.seiko.imageloader.Bitmap
|
||||
import com.seiko.imageloader.BitmapConfig
|
||||
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryKey
|
||||
import com.seiko.imageloader.component.ComponentRegistryBuilder
|
||||
import com.seiko.imageloader.component.setupDefaultComponents
|
||||
import com.seiko.imageloader.option.Options
|
||||
import com.seiko.imageloader.option.OptionsBuilder
|
||||
import com.seiko.imageloader.option.androidContext
|
||||
import okio.Path.Companion.toOkioPath
|
||||
|
||||
actual fun OptionsBuilder.configure(contextWrapper: ContextWrapper) {
|
||||
imageConfig = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
Options.ImageConfig.ARGB_8888
|
||||
bitmapConfig = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
BitmapConfig.ARGB_8888
|
||||
} else {
|
||||
Options.ImageConfig.HARDWARE
|
||||
BitmapConfig.HARDWARE
|
||||
}
|
||||
androidContext(contextWrapper)
|
||||
}
|
||||
@@ -42,5 +44,5 @@ actual fun DiskCacheBuilder.configure(
|
||||
maxSizeBytes(1024 * 1024 * 150) // 150 MB
|
||||
}
|
||||
|
||||
actual fun MemoryCacheBuilder.configure(contextWrapper: ContextWrapper) {
|
||||
actual fun MemoryCacheBuilder<MemoryKey, Bitmap>.configure(contextWrapper: ContextWrapper) {
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@ fun getMaterialDialogProperties(
|
||||
dismissOnClickOutside = dismissOnClickOutside,
|
||||
securePolicy = securePolicy,
|
||||
usePlatformDefaultWidth = usePlatformDefaultWidth,
|
||||
position = position,
|
||||
size = size,
|
||||
title = title,
|
||||
icon = icon,
|
||||
resizable = resizable,
|
||||
windowPosition = position,
|
||||
windowSize = size,
|
||||
windowTitle = title,
|
||||
windowIcon = icon,
|
||||
windowIsResizable = resizable,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,9 +13,11 @@ import ca.gosyer.jui.domain.server.service.ServerPreferences
|
||||
import ca.gosyer.jui.domain.source.model.Source
|
||||
import ca.gosyer.jui.ui.base.ImageCache
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import com.seiko.imageloader.Bitmap
|
||||
import com.seiko.imageloader.ImageLoader
|
||||
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryKey
|
||||
import com.seiko.imageloader.component.ComponentRegistryBuilder
|
||||
import com.seiko.imageloader.component.fetcher.MokoResourceFetcher
|
||||
import com.seiko.imageloader.component.keyer.Keyer
|
||||
@@ -138,4 +140,4 @@ expect fun DiskCacheBuilder.configure(
|
||||
cacheDir: String,
|
||||
)
|
||||
|
||||
expect fun MemoryCacheBuilder.configure(contextWrapper: ContextWrapper)
|
||||
expect fun MemoryCacheBuilder<MemoryKey, Bitmap>.configure(contextWrapper: ContextWrapper)
|
||||
|
||||
@@ -27,7 +27,6 @@ import ca.gosyer.jui.ui.base.state.getStateFlow
|
||||
import ca.gosyer.jui.ui.util.lang.CollatorComparator
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
@@ -198,7 +197,7 @@ class LibraryScreenViewModel
|
||||
log.warn(it) { "Failed to get manga list from category ${category.name}" }
|
||||
library.mangaMap.setError(category.id, it)
|
||||
}
|
||||
.launchIn(coroutineScope)
|
||||
.launchIn(scope)
|
||||
}
|
||||
}
|
||||
.catch {
|
||||
|
||||
@@ -37,7 +37,7 @@ fun LibraryPager(
|
||||
) {
|
||||
if (categories.isEmpty()) return
|
||||
|
||||
HorizontalPager(categories.size, state = pagerState) {
|
||||
HorizontalPager(state = pagerState) {
|
||||
when (val library = getLibraryForPage(categories[it].id).value) {
|
||||
CategoryState.Loading -> LoadingScreen()
|
||||
is CategoryState.Failed -> ErrorScreen(library.e.message)
|
||||
|
||||
@@ -12,7 +12,6 @@ import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.forEachGesture
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -90,7 +89,9 @@ fun LibraryScreenContent(
|
||||
}
|
||||
|
||||
BoxWithConstraints {
|
||||
val pagerState = rememberPagerState(selectedCategoryIndex)
|
||||
val pagerState = rememberPagerState(selectedCategoryIndex) {
|
||||
(libraryState as? LibraryState.Loaded)?.categories?.size ?: 1
|
||||
}
|
||||
LaunchedEffect(pagerState.isScrollInProgress to pagerState.currentPage) {
|
||||
if (!pagerState.isScrollInProgress && pagerState.currentPage != selectedCategoryIndex) {
|
||||
onPageChanged(pagerState.currentPage)
|
||||
@@ -240,11 +241,7 @@ fun WideLibraryScreenContent(
|
||||
if (showingMenu) {
|
||||
Box(
|
||||
Modifier.fillMaxSize().pointerInput(Unit) {
|
||||
forEachGesture {
|
||||
detectTapGestures {
|
||||
setShowingMenu(false)
|
||||
}
|
||||
}
|
||||
detectTapGestures(onTap = { setShowingMenu(false) })
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -295,7 +292,7 @@ fun ThinLibraryScreenContent(
|
||||
) {
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
ModalBottomSheetValue.Hidden,
|
||||
confirmStateChange = {
|
||||
confirmValueChange = {
|
||||
when (it) {
|
||||
ModalBottomSheetValue.Hidden -> setShowingSheet(false)
|
||||
ModalBottomSheetValue.Expanded,
|
||||
|
||||
@@ -49,7 +49,7 @@ fun LibrarySheet(
|
||||
librarySort: @Composable () -> Unit,
|
||||
libraryDisplay: @Composable () -> Unit,
|
||||
) {
|
||||
val pagerState = rememberPagerState()
|
||||
val pagerState = rememberPagerState { LibrarySheetTabs.values().size }
|
||||
val selectedPage = pagerState.currentPage
|
||||
val scope = rememberCoroutineScope()
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
@@ -72,7 +72,6 @@ fun LibrarySheet(
|
||||
}
|
||||
}
|
||||
HorizontalPager(
|
||||
pageCount = LibrarySheetTabs.values().size,
|
||||
state = pagerState,
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
|
||||
@@ -13,7 +13,7 @@ import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.consumedWindowInsets
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -110,7 +110,11 @@ fun WideMainMenu(
|
||||
}
|
||||
withDisplayController(controller) {
|
||||
val insets = WindowInsets.navigationBars.only(WindowInsetsSides.Start)
|
||||
MainWindow(navigator, Modifier.padding(start = startPadding).windowInsetsPadding(insets).consumedWindowInsets(insets))
|
||||
MainWindow(navigator,
|
||||
Modifier.padding(start = startPadding)
|
||||
.windowInsetsPadding(insets)
|
||||
.consumeWindowInsets(insets)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import ca.gosyer.jui.uicore.insets.statusBars
|
||||
import ca.gosyer.jui.uicore.resources.stringResource
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.ui.compose.Libraries
|
||||
import com.mikepenz.aboutlibraries.ui.compose.util.StableLibrary
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
@@ -58,10 +59,10 @@ fun LicensesContent() {
|
||||
val state = rememberLazyListState()
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Libraries(
|
||||
libraries = remember(libs) { libs.libraries.toImmutableList() },
|
||||
libraries = remember(libs) { libs.libraries.map { StableLibrary(it) }.toImmutableList() },
|
||||
lazyListState = state,
|
||||
onLibraryClick = {
|
||||
it.website?.let(uriHandler::openUri)
|
||||
it.library.website?.let(uriHandler::openUri)
|
||||
},
|
||||
contentPadding = WindowInsets.bottomNav.add(
|
||||
WindowInsets.navigationBars.only(
|
||||
|
||||
@@ -33,7 +33,6 @@ import ca.gosyer.jui.ui.base.chapter.ChapterDownloadState
|
||||
import ca.gosyer.jui.ui.base.model.StableHolder
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
@@ -94,7 +93,7 @@ class MangaScreenViewModel
|
||||
private val loadingManga = MutableStateFlow(true)
|
||||
private val loadingChapters = MutableStateFlow(true)
|
||||
val isLoading = combine(loadingManga, loadingChapters) { a, b -> a || b }
|
||||
.stateIn(coroutineScope, SharingStarted.Eagerly, true)
|
||||
.stateIn(scope, SharingStarted.Eagerly, true)
|
||||
|
||||
val categories = getCategories.asFlow(true)
|
||||
.map { it.toImmutableList() }
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
package ca.gosyer.jui.ui.reader
|
||||
|
||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPage
|
||||
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
||||
import ca.gosyer.jui.domain.server.Http
|
||||
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
||||
import ca.gosyer.jui.ui.reader.loader.PagesState
|
||||
import ca.gosyer.jui.ui.reader.loader.TachideskPageLoader
|
||||
@@ -23,7 +23,7 @@ import org.lighthousegames.logging.logging
|
||||
|
||||
class ChapterLoader(
|
||||
private val readerPreferences: ReaderPreferences,
|
||||
private val getChapterPage: GetChapterPage,
|
||||
private val http: Http,
|
||||
private val chapterCache: DiskCache,
|
||||
private val bitmapDecoderFactory: BitmapDecoderFactory,
|
||||
) {
|
||||
@@ -34,7 +34,7 @@ class ChapterLoader(
|
||||
chapter.state = ReaderChapter.State.Loading
|
||||
log.debug { "Loading pages for ${chapter.chapter.name}" }
|
||||
|
||||
val loader = TachideskPageLoader(chapter, readerPreferences, getChapterPage, chapterCache, bitmapDecoderFactory)
|
||||
val loader = TachideskPageLoader(chapter, readerPreferences, http, chapterCache, bitmapDecoderFactory)
|
||||
|
||||
val pages = loader.getPages()
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import ca.gosyer.jui.domain.manga.model.MangaMeta
|
||||
import ca.gosyer.jui.domain.reader.ReaderModeWatch
|
||||
import ca.gosyer.jui.domain.reader.model.Direction
|
||||
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
||||
import ca.gosyer.jui.domain.server.Http
|
||||
import ca.gosyer.jui.ui.base.ChapterCache
|
||||
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
||||
import ca.gosyer.jui.ui.base.model.StableHolder
|
||||
@@ -82,6 +83,7 @@ class ReaderMenuViewModel
|
||||
private val updateMangaMeta: UpdateMangaMeta,
|
||||
private val updateChapterMeta: UpdateChapterMeta,
|
||||
private val chapterCache: ChapterCache,
|
||||
private val http: Http,
|
||||
contextWrapper: ContextWrapper,
|
||||
@Assisted private val params: Params,
|
||||
) : ViewModel(contextWrapper) {
|
||||
@@ -152,7 +154,7 @@ class ReaderMenuViewModel
|
||||
|
||||
private val loader = ChapterLoader(
|
||||
readerPreferences = readerPreferences,
|
||||
getChapterPage = getChapterPage,
|
||||
http = http,
|
||||
chapterCache = chapterCache,
|
||||
bitmapDecoderFactory = BitmapDecoderFactory(contextWrapper),
|
||||
)
|
||||
|
||||
@@ -13,6 +13,7 @@ import ca.gosyer.jui.core.lang.PriorityChannel
|
||||
import ca.gosyer.jui.core.lang.throwIfCancellation
|
||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPage
|
||||
import ca.gosyer.jui.domain.reader.service.ReaderPreferences
|
||||
import ca.gosyer.jui.domain.server.Http
|
||||
import ca.gosyer.jui.ui.base.image.BitmapDecoderFactory
|
||||
import ca.gosyer.jui.ui.base.model.StableHolder
|
||||
import ca.gosyer.jui.ui.reader.model.ReaderChapter
|
||||
@@ -23,10 +24,10 @@ import com.seiko.imageloader.asImageBitmap
|
||||
import com.seiko.imageloader.cache.disk.DiskCache
|
||||
import com.seiko.imageloader.component.decoder.DecodeResult
|
||||
import com.seiko.imageloader.model.DataSource
|
||||
import com.seiko.imageloader.model.ImageRequest
|
||||
import com.seiko.imageloader.model.ImageResult
|
||||
import com.seiko.imageloader.option.Options
|
||||
import io.ktor.client.plugins.onDownload
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.statement.bodyAsChannel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -39,6 +40,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
@@ -53,7 +55,7 @@ import org.lighthousegames.logging.logging
|
||||
class TachideskPageLoader(
|
||||
val chapter: ReaderChapter,
|
||||
readerPreferences: ReaderPreferences,
|
||||
private val getChapterPage: GetChapterPage,
|
||||
private val http: Http,
|
||||
private val chapterCache: DiskCache,
|
||||
private val bitmapDecoderFactory: BitmapDecoderFactory,
|
||||
) : PageLoader() {
|
||||
@@ -109,11 +111,15 @@ class TachideskPageLoader(
|
||||
|
||||
private suspend fun fetchImage(page: ReaderPage) {
|
||||
log.debug { "Loading page ${page.index}" }
|
||||
getChapterPage.asFlow(chapter.chapter, page.index) {
|
||||
flow {
|
||||
val response = http.get("api/v1/manga/${chapter.chapter.mangaId}/chapter/${chapter.chapter.index}/page/${page.index}") {
|
||||
onDownload { bytesSentTotal, contentLength ->
|
||||
page.progress.value = (bytesSentTotal.toFloat() / contentLength).coerceAtMost(1.0F)
|
||||
}
|
||||
}
|
||||
|
||||
emit(response)
|
||||
}
|
||||
.onEach {
|
||||
putImageInCache(it, page)
|
||||
page.bitmap.value = StableHolder { getImageFromCache(page) }
|
||||
@@ -134,7 +140,7 @@ class TachideskPageLoader(
|
||||
response: HttpResponse,
|
||||
page: ReaderPage,
|
||||
) {
|
||||
val editor = chapterCache.edit(page.cacheKey)
|
||||
val editor = chapterCache.openEditor(page.cacheKey)
|
||||
?: throw Exception("Couldn't open cache")
|
||||
try {
|
||||
FileSystem.SYSTEM.write(editor.data) {
|
||||
@@ -150,18 +156,17 @@ class TachideskPageLoader(
|
||||
}
|
||||
|
||||
private suspend fun getImageFromCache(page: ReaderPage): ReaderPage.ImageDecodeState {
|
||||
return chapterCache[page.cacheKey]?.use {
|
||||
return chapterCache.openSnapshot(page.cacheKey)?.use {
|
||||
it.source().use { source ->
|
||||
val decoder = bitmapDecoderFactory.create(
|
||||
ImageResult.Source(
|
||||
ImageRequest(Any()),
|
||||
ImageResult.OfSource(
|
||||
source,
|
||||
DataSource.Engine,
|
||||
),
|
||||
Options(),
|
||||
)
|
||||
if (decoder != null) {
|
||||
runCatching { decoder.decode() as DecodeResult.Bitmap }
|
||||
runCatching { decoder.decode() as DecodeResult.OfBitmap }
|
||||
.mapCatching {
|
||||
ReaderPage.ImageDecodeState.Success(
|
||||
it.bitmap.asImageBitmap().also {
|
||||
|
||||
@@ -86,6 +86,7 @@ class SettingsServerScreen : Screen {
|
||||
|
||||
expect class SettingsServerHostViewModel : ViewModel
|
||||
|
||||
@Composable
|
||||
expect fun getServerHostItems(viewModel: @Composable () -> SettingsServerHostViewModel): LazyListScope.() -> Unit
|
||||
|
||||
class SettingsServerViewModel
|
||||
|
||||
@@ -12,7 +12,6 @@ import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.forEachGesture
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
@@ -228,11 +227,7 @@ private fun SourceWideScreenContent(
|
||||
if (showingFilters && !isLatest) {
|
||||
Box(
|
||||
Modifier.fillMaxSize().pointerInput(loading) {
|
||||
forEachGesture {
|
||||
detectTapGestures {
|
||||
setShowingFilters(false)
|
||||
}
|
||||
}
|
||||
detectTapGestures(onTap = { setShowingFilters(false) })
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -287,7 +282,7 @@ private fun SourceThinScreenContent(
|
||||
) {
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
ModalBottomSheetValue.Hidden,
|
||||
confirmStateChange = {
|
||||
confirmValueChange = {
|
||||
when (it) {
|
||||
ModalBottomSheetValue.Hidden -> setShowingFilters(false)
|
||||
ModalBottomSheetValue.Expanded,
|
||||
@@ -364,11 +359,7 @@ private fun SourceThinScreenContent(
|
||||
if (showingFilters && !isLatest) {
|
||||
Box(
|
||||
Modifier.fillMaxSize().pointerInput(loading) {
|
||||
forEachGesture {
|
||||
detectTapGestures {
|
||||
setShowingFilters(false)
|
||||
}
|
||||
}
|
||||
detectTapGestures(onTap = { setShowingFilters(false) })
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,13 +8,35 @@ package ca.gosyer.jui.ui.base.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpOffset
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
actual typealias TooltipPlacement = androidx.compose.foundation.TooltipPlacement
|
||||
|
||||
actual typealias CursorPointImpl = androidx.compose.foundation.TooltipPlacement.CursorPoint
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
actual class CursorPointImpl actual constructor(
|
||||
offset: DpOffset,
|
||||
alignment: Alignment,
|
||||
windowMargin: Dp,
|
||||
) : TooltipPlacement by androidx.compose.foundation.TooltipPlacement.CursorPoint(
|
||||
offset = offset,
|
||||
alignment = alignment,
|
||||
windowMargin = windowMargin
|
||||
)
|
||||
|
||||
actual typealias ComponentRectImpl = androidx.compose.foundation.TooltipPlacement.ComponentRect
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
actual class ComponentRectImpl actual constructor(
|
||||
anchor: Alignment,
|
||||
alignment: Alignment,
|
||||
offset: DpOffset,
|
||||
) : TooltipPlacement by androidx.compose.foundation.TooltipPlacement.ComponentRect(
|
||||
anchor = anchor,
|
||||
alignment = alignment,
|
||||
offset = offset
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
|
||||
@@ -9,8 +9,10 @@ package ca.gosyer.jui.ui.base.image
|
||||
import ca.gosyer.jui.core.io.userDataDir
|
||||
import ca.gosyer.jui.domain.server.Http
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import com.seiko.imageloader.Bitmap
|
||||
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryKey
|
||||
import com.seiko.imageloader.component.ComponentRegistryBuilder
|
||||
import com.seiko.imageloader.component.setupDefaultComponents
|
||||
import com.seiko.imageloader.option.OptionsBuilder
|
||||
@@ -33,5 +35,5 @@ actual fun DiskCacheBuilder.configure(
|
||||
maxSizeBytes(1024 * 1024 * 150) // 150 MB
|
||||
}
|
||||
|
||||
actual fun MemoryCacheBuilder.configure(contextWrapper: ContextWrapper) {
|
||||
actual fun MemoryCacheBuilder<MemoryKey, Bitmap>.configure(contextWrapper: ContextWrapper) {
|
||||
}
|
||||
|
||||
@@ -8,8 +8,10 @@ package ca.gosyer.jui.ui.base.image
|
||||
|
||||
import ca.gosyer.jui.domain.server.Http
|
||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||
import com.seiko.imageloader.Bitmap
|
||||
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||
import com.seiko.imageloader.cache.memory.MemoryKey
|
||||
import com.seiko.imageloader.cache.memory.maxSizePercent
|
||||
import com.seiko.imageloader.component.ComponentRegistryBuilder
|
||||
import com.seiko.imageloader.component.setupDefaultComponents
|
||||
@@ -47,6 +49,6 @@ private fun getCacheDir(): String {
|
||||
)!!.path.orEmpty()
|
||||
}
|
||||
|
||||
actual fun MemoryCacheBuilder.configure(contextWrapper: ContextWrapper) {
|
||||
actual fun MemoryCacheBuilder<MemoryKey, Bitmap>.configure(contextWrapper: ContextWrapper) {
|
||||
maxSizePercent(0.25)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ plugins {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android {
|
||||
androidTarget {
|
||||
compilations {
|
||||
all {
|
||||
kotlinOptions.jvmTarget = Config.androidJvmTarget.toString()
|
||||
@@ -28,6 +28,21 @@ kotlin {
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
|
||||
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class)
|
||||
applyHierarchyTemplate {
|
||||
common {
|
||||
group("jvm") {
|
||||
withAndroidTarget()
|
||||
withJvm()
|
||||
}
|
||||
group("ios") {
|
||||
withIosX64()
|
||||
withIosArm64()
|
||||
withIosSimulatorArm64()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings {
|
||||
@@ -63,29 +78,24 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
val jvmMain by creating {
|
||||
dependsOn(commonMain)
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(compose.desktop.currentOs)
|
||||
}
|
||||
}
|
||||
val jvmTest by creating {
|
||||
dependsOn(commonTest)
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
}
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
}
|
||||
val desktopTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
dependsOn(jvmMain)
|
||||
dependencies {
|
||||
api(libs.bundles.compose.android)
|
||||
api(libs.androidx.core)
|
||||
@@ -93,23 +103,6 @@ kotlin {
|
||||
}
|
||||
}
|
||||
val androidUnitTest by getting {
|
||||
dependsOn(jvmTest)
|
||||
}
|
||||
|
||||
val iosMain by creating {
|
||||
dependsOn(commonMain)
|
||||
}
|
||||
val iosTest by creating {
|
||||
dependsOn(commonTest)
|
||||
}
|
||||
|
||||
listOf(
|
||||
"iosX64",
|
||||
"iosArm64",
|
||||
"iosSimulatorArm64",
|
||||
).forEach {
|
||||
getByName(it + "Main").dependsOn(iosMain)
|
||||
getByName(it + "Test").dependsOn(iosTest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,9 +35,11 @@ import androidx.compose.ui.graphics.drawscope.DrawScope.Companion.DefaultFilterQ
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ca.gosyer.jui.uicore.components.LoadingScreen
|
||||
import com.seiko.imageloader.ImageRequestState
|
||||
import com.seiko.imageloader.model.ImageAction
|
||||
import com.seiko.imageloader.model.ImageRequest
|
||||
import com.seiko.imageloader.rememberAsyncImagePainter
|
||||
import com.seiko.imageloader.rememberImageAction
|
||||
import com.seiko.imageloader.rememberImageActionPainter
|
||||
import com.seiko.imageloader.rememberImagePainter
|
||||
import org.lighthousegames.logging.logging
|
||||
|
||||
private val log = logging()
|
||||
@@ -84,32 +86,31 @@ fun ImageLoaderImage(
|
||||
) {
|
||||
key(data) {
|
||||
val request = remember { ImageRequest(data) }
|
||||
val painter = rememberAsyncImagePainter(
|
||||
request,
|
||||
contentScale = contentScale,
|
||||
filterQuality = filterQuality,
|
||||
)
|
||||
if (animationSpec != null) {
|
||||
val imageAction by rememberImageAction(request)
|
||||
|
||||
val progress = remember { mutableStateOf(-1F) }
|
||||
val error = remember { mutableStateOf<Throwable?>(null) }
|
||||
val state by derivedStateOf {
|
||||
when (val state = painter.requestState) {
|
||||
is ImageRequestState.Failure -> {
|
||||
when (val action = imageAction) {
|
||||
is ImageAction.Failure -> {
|
||||
progress.value = 0.0F
|
||||
error.value = state.error
|
||||
error.value = action.error
|
||||
ImageLoaderImageState.Failure
|
||||
}
|
||||
is ImageRequestState.Loading -> {
|
||||
is ImageAction.Loading -> {
|
||||
progress.value = 0.0F
|
||||
ImageLoaderImageState.Loading
|
||||
}
|
||||
ImageRequestState.Success -> {
|
||||
is ImageAction.Success -> {
|
||||
progress.value = 1.0F
|
||||
ImageLoaderImageState.Success
|
||||
}
|
||||
else -> {
|
||||
ImageLoaderImageState.Loading
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animationSpec != null) {
|
||||
Crossfade(state, animationSpec = animationSpec, modifier = modifier) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment) {
|
||||
when (it) {
|
||||
@@ -117,7 +118,10 @@ fun ImageLoaderImage(
|
||||
onLoading(progress.value)
|
||||
}
|
||||
ImageLoaderImageState.Success -> Image(
|
||||
painter = painter,
|
||||
painter = rememberImageActionPainter(
|
||||
imageAction,
|
||||
filterQuality = filterQuality
|
||||
),
|
||||
contentDescription = contentDescription,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
alignment = alignment,
|
||||
@@ -136,7 +140,7 @@ fun ImageLoaderImage(
|
||||
} else {
|
||||
Box(modifier, contentAlignment) {
|
||||
Image(
|
||||
painter = painter,
|
||||
painter = rememberImagePainter(request, filterQuality = filterQuality),
|
||||
contentDescription = contentDescription,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
alignment = alignment,
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
package ca.gosyer.jui.uicore.pager
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.gestures.FlingBehavior
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.snapping.SnapLayoutInfoProvider
|
||||
import androidx.compose.foundation.gestures.snapping.SnapPositionInLayout
|
||||
import androidx.compose.foundation.gestures.snapping.SnapPositionInLayout.Companion.CenterToCenter
|
||||
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -38,6 +41,8 @@ import androidx.compose.ui.util.fastForEach
|
||||
import androidx.compose.ui.util.fastMaxBy
|
||||
import androidx.compose.ui.util.fastSumBy
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sign
|
||||
|
||||
@Composable
|
||||
fun VerticalPager(
|
||||
@@ -229,9 +234,7 @@ class PagerState(
|
||||
// https://android.googlesource.com/platform/frameworks/support/+/refs/changes/78/2160778/35/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/gestures/snapping/LazyListSnapLayoutInfoProvider.kt
|
||||
private fun lazyListSnapLayoutInfoProvider(
|
||||
lazyListState: LazyListState,
|
||||
positionInLayout: (layoutSize: Float, itemSize: Float) -> Float = { layoutSize, itemSize ->
|
||||
layoutSize / 2f - itemSize / 2f
|
||||
},
|
||||
positionInLayout: SnapPositionInLayout = CenterToCenter
|
||||
) = object : SnapLayoutInfoProvider {
|
||||
private val layoutInfo: LazyListLayoutInfo
|
||||
get() = lazyListState.layoutInfo
|
||||
@@ -239,13 +242,21 @@ private fun lazyListSnapLayoutInfoProvider(
|
||||
// Single page snapping is the default
|
||||
override fun Density.calculateApproachOffset(initialVelocity: Float): Float = 0f
|
||||
|
||||
override fun Density.calculateSnappingOffsetBounds(): ClosedFloatingPointRange<Float> {
|
||||
override fun Density.calculateSnappingOffset(currentVelocity: Float): Float {
|
||||
var lowerBoundOffset = Float.NEGATIVE_INFINITY
|
||||
var upperBoundOffset = Float.POSITIVE_INFINITY
|
||||
|
||||
layoutInfo.visibleItemsInfo.fastForEach { item ->
|
||||
val offset =
|
||||
calculateDistanceToDesiredSnapPosition(layoutInfo, item, positionInLayout)
|
||||
calculateDistanceToDesiredSnapPosition(
|
||||
mainAxisViewPortSize = layoutInfo.singleAxisViewportSize,
|
||||
beforeContentPadding = layoutInfo.beforeContentPadding,
|
||||
afterContentPadding = layoutInfo.afterContentPadding,
|
||||
itemSize = item.size,
|
||||
itemOffset = item.offset,
|
||||
itemIndex = item.index,
|
||||
snapPositionInLayout = positionInLayout
|
||||
)
|
||||
|
||||
// Find item that is closest to the center
|
||||
if (offset <= 0 && offset > lowerBoundOffset) {
|
||||
@@ -258,7 +269,58 @@ private fun lazyListSnapLayoutInfoProvider(
|
||||
}
|
||||
}
|
||||
|
||||
return lowerBoundOffset.rangeTo(upperBoundOffset)
|
||||
return calculateFinalOffset(
|
||||
currentVelocity,
|
||||
lowerBoundOffset,
|
||||
upperBoundOffset
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
private fun Density.calculateDistanceToDesiredSnapPosition(
|
||||
mainAxisViewPortSize: Int,
|
||||
beforeContentPadding: Int,
|
||||
afterContentPadding: Int,
|
||||
itemSize: Int,
|
||||
itemOffset: Int,
|
||||
itemIndex: Int,
|
||||
snapPositionInLayout: SnapPositionInLayout
|
||||
): Float {
|
||||
val containerSize = mainAxisViewPortSize - beforeContentPadding - afterContentPadding
|
||||
|
||||
val desiredDistance = with(snapPositionInLayout) {
|
||||
position(containerSize, itemSize, itemIndex)
|
||||
}.toFloat()
|
||||
|
||||
return itemOffset - desiredDistance
|
||||
}
|
||||
|
||||
|
||||
private fun calculateFinalOffset(velocity: Float, lowerBound: Float, upperBound: Float): Float {
|
||||
|
||||
fun Float.isValidDistance(): Boolean {
|
||||
return this != Float.POSITIVE_INFINITY && this != Float.NEGATIVE_INFINITY
|
||||
}
|
||||
|
||||
val finalDistance = when (sign(velocity)) {
|
||||
0f -> {
|
||||
if (abs(upperBound) <= abs(lowerBound)) {
|
||||
upperBound
|
||||
} else {
|
||||
lowerBound
|
||||
}
|
||||
}
|
||||
|
||||
1f -> upperBound
|
||||
-1f -> lowerBound
|
||||
else -> 0f
|
||||
}
|
||||
|
||||
return if (finalDistance.isValidDistance()) {
|
||||
finalDistance
|
||||
} else {
|
||||
0f
|
||||
}
|
||||
}
|
||||
|
||||
override fun Density.calculateSnapStepSize(): Float =
|
||||
@@ -277,20 +339,5 @@ private fun rememberLazyListSnapFlingBehavior(lazyListState: LazyListState): Fli
|
||||
return rememberSnapFlingBehavior(snappingLayout)
|
||||
}
|
||||
|
||||
private fun calculateDistanceToDesiredSnapPosition(
|
||||
layoutInfo: LazyListLayoutInfo,
|
||||
item: LazyListItemInfo,
|
||||
positionInLayout: (layoutSize: Float, itemSize: Float) -> Float,
|
||||
): Float {
|
||||
val containerSize =
|
||||
with(layoutInfo) { singleAxisViewportSize - beforeContentPadding - afterContentPadding }
|
||||
|
||||
val desiredDistance =
|
||||
positionInLayout(containerSize.toFloat(), item.size.toFloat())
|
||||
|
||||
val itemCurrentPosition = item.offset
|
||||
return itemCurrentPosition - desiredDistance
|
||||
}
|
||||
|
||||
private val LazyListLayoutInfo.singleAxisViewportSize: Int
|
||||
get() = if (orientation == Orientation.Vertical) viewportSize.height else viewportSize.width
|
||||
|
||||
@@ -10,7 +10,7 @@ import ca.gosyer.jui.core.lang.launchUI
|
||||
import ca.gosyer.jui.core.prefs.Preference
|
||||
import ca.gosyer.jui.uicore.prefs.PreferenceMutableStateFlow
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.coroutineScope
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
abstract class ViewModel(private val contextWrapper: ContextWrapper) : ScreenModel {
|
||||
protected open val scope: CoroutineScope
|
||||
get() = coroutineScope
|
||||
get() = screenModelScope
|
||||
|
||||
fun <T> Preference<T>.asStateFlow() = PreferenceMutableStateFlow(this, scope)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package ca.gosyer.jui.uicore.components
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.hoverable
|
||||
import androidx.compose.foundation.interaction.HoverInteraction
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
@@ -14,12 +15,14 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalCoroutinesApi::class)
|
||||
actual fun Modifier.buttonModifier(
|
||||
onClick: () -> Unit,
|
||||
onHintClick: () -> Unit,
|
||||
|
||||
Reference in New Issue
Block a user