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