mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
More stuff to the shared jvm module, android compatibility WIP
This commit is contained in:
@@ -128,6 +128,26 @@ subprojects {
|
||||
toolVersion = "0.8.7"
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
plugins.withType<org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper> {
|
||||
configure<org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension> {
|
||||
if (!Config.androidDev) {
|
||||
sourceSets.addSrcDir("desktopMain", "jvmMain")
|
||||
sourceSets.addSrcDir("desktopTest", "jvmTest")
|
||||
}
|
||||
sourceSets.addSrcDir("androidMain", "jvmMain")
|
||||
sourceSets.addSrcDir("androidTest", "jvmTest")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.addSrcDir(configuration: String, srcDir: String) {
|
||||
filter { it.name.contains(configuration) }
|
||||
.forEach {
|
||||
it.kotlin.srcDir("src/$srcDir/kotlin")
|
||||
}
|
||||
}
|
||||
|
||||
fun isNonStable(version: String): Boolean {
|
||||
|
||||
@@ -12,4 +12,6 @@ object Config {
|
||||
|
||||
val desktopJvmTarget = JavaVersion.VERSION_16
|
||||
val androidJvmTarget = JavaVersion.VERSION_11
|
||||
|
||||
const val androidDev = false
|
||||
}
|
||||
@@ -63,7 +63,6 @@ kotlin {
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
kotlin.srcDir("src/jvmMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/desktopMain/kotlin")
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
@@ -71,20 +70,17 @@ kotlin {
|
||||
}
|
||||
}
|
||||
val desktopTest by getting {
|
||||
kotlin.srcDir("src/jvmTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/desktopTest/kotlin")
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
kotlin.srcDir("src/jvmMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidRelease/kotlin")
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
}
|
||||
val androidTest by getting {
|
||||
kotlin.srcDir("src/jvmTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidReleaseTest/kotlin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,27 +57,23 @@ kotlin {
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
kotlin.srcDir("src/jvmMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/desktopMain/kotlin")
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
}
|
||||
val desktopTest by getting {
|
||||
kotlin.srcDir("src/jvmTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/desktopTest/kotlin")
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
kotlin.srcDir("src/jvmMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidRelease/kotlin")
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
}
|
||||
val androidTest by getting {
|
||||
kotlin.srcDir("src/jvmTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidReleaseTest/kotlin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ kotlin {
|
||||
api(libs.voyagerNavigation)
|
||||
api(libs.voyagerTransitions)
|
||||
api(libs.materialDialogsCore)
|
||||
api(libs.accompanistPager)
|
||||
api(libs.accompanistFlowLayout)
|
||||
api(libs.krokiCoroutines)
|
||||
api(projects.core)
|
||||
api(projects.i18n)
|
||||
api(projects.data)
|
||||
@@ -65,31 +68,24 @@ kotlin {
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
kotlin.srcDir("src/jvmMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/desktopMain/kotlin")
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
api(libs.coroutinesSwing)
|
||||
api(libs.accompanistPager)
|
||||
api(libs.accompanistFlowLayout)
|
||||
api(libs.krokiCoroutines)
|
||||
}
|
||||
}
|
||||
val desktopTest by getting {
|
||||
kotlin.srcDir("src/jvmTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/desktopTest/kotlin")
|
||||
}
|
||||
|
||||
val androidMain by getting {
|
||||
kotlin.srcDir("src/jvmMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidMain/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidRelease/kotlin")
|
||||
dependencies {
|
||||
api(kotlin("stdlib-jdk8"))
|
||||
}
|
||||
}
|
||||
val androidTest by getting {
|
||||
kotlin.srcDir("src/jvmTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidTest/kotlin")
|
||||
kotlin.srcDir("build/generated/ksp/androidReleaseTest/kotlin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import ca.gosyer.core.di.AppScope
|
||||
import ca.gosyer.data.DataComponent
|
||||
import ca.gosyer.data.create
|
||||
import ca.gosyer.ui.base.UiComponent
|
||||
import ca.gosyer.ui.base.create
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import me.tatarka.inject.annotations.Component
|
||||
|
||||
@AppScope
|
||||
@Component
|
||||
actual abstract class AppComponent constructor(
|
||||
val context: Context,
|
||||
actual val dataComponent: DataComponent = DataComponent.create(context),
|
||||
@Component
|
||||
actual val uiComponent: UiComponent = UiComponent.create(dataComponent)
|
||||
) {
|
||||
actual abstract val contextWrapper: ContextWrapper
|
||||
companion object {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private var appComponentInstance: AppComponent? = null
|
||||
|
||||
fun getInstance(context: Context) = appComponentInstance ?: create(context)
|
||||
.also { appComponentInstance = it }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.base
|
||||
|
||||
import ca.gosyer.core.di.AppScope
|
||||
import ca.gosyer.data.DataComponent
|
||||
import ca.gosyer.ui.base.image.KamelConfigProvider
|
||||
import ca.gosyer.ui.base.vm.ViewModelFactoryImpl
|
||||
import ca.gosyer.uicore.vm.LocalViewModelFactory
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import io.kamel.image.config.LocalKamelConfig
|
||||
import io.kamel.image.config.resourcesFetcher
|
||||
import me.tatarka.inject.annotations.Component
|
||||
import me.tatarka.inject.annotations.Provides
|
||||
|
||||
@AppScope
|
||||
@Component
|
||||
actual abstract class UiComponent(
|
||||
@Component actual val dataComponent: DataComponent
|
||||
) {
|
||||
protected actual abstract val kamelConfigProvider: KamelConfigProvider
|
||||
|
||||
actual abstract val viewModelFactory: ViewModelFactoryImpl
|
||||
|
||||
actual abstract val kamelConfig: KamelConfig
|
||||
|
||||
@get:AppScope
|
||||
@get:Provides
|
||||
actual protected val kamelConfigFactory: KamelConfig
|
||||
get() = kamelConfigProvider.get { resourcesFetcher(dataComponent.context) }
|
||||
|
||||
actual fun getHooks() = arrayOf(
|
||||
LocalViewModelFactory provides viewModelFactory,
|
||||
LocalKamelConfig provides kamelConfig
|
||||
)
|
||||
|
||||
actual companion object
|
||||
}
|
||||
@@ -32,6 +32,15 @@ actual fun VerticalScrollbar(
|
||||
interactionSource: MutableInteractionSource
|
||||
) {}
|
||||
|
||||
@Composable
|
||||
actual fun HorizontalScrollbar(
|
||||
adapter: ScrollbarAdapter,
|
||||
modifier: Modifier,
|
||||
reverseLayout: Boolean,
|
||||
style: ScrollbarStyle,
|
||||
interactionSource: MutableInteractionSource
|
||||
) {}
|
||||
|
||||
@Composable
|
||||
actual fun rememberScrollbarAdapter(
|
||||
scrollState: ScrollState
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.base.prefs
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
internal actual fun Color.toHsv(): FloatArray {
|
||||
fun Float.toIntColor() = (this * 256).toInt()
|
||||
val result = floatArrayOf(0f, 0f, 0f)
|
||||
android.graphics.Color.RGBToHSV(red.toIntColor(), green.toIntColor(), blue.toIntColor(), result)
|
||||
return result
|
||||
}
|
||||
|
||||
internal actual fun hexStringToColor(hex: String): Color? {
|
||||
return try {
|
||||
val color = android.graphics.Color.parseColor(hex)
|
||||
Color(color)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.reader
|
||||
|
||||
actual fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.util.compose
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import io.ktor.utils.io.ByteReadChannel
|
||||
import io.ktor.utils.io.jvm.javaio.toInputStream
|
||||
|
||||
actual suspend fun ByteReadChannel.toImageBitmap(): ImageBitmap {
|
||||
return BitmapFactory.decodeStream(toInputStream()).asImageBitmap()
|
||||
}
|
||||
@@ -11,19 +11,21 @@ import ca.gosyer.data.DataComponent
|
||||
import ca.gosyer.data.create
|
||||
import ca.gosyer.ui.base.UiComponent
|
||||
import ca.gosyer.ui.base.create
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import me.tatarka.inject.annotations.Component
|
||||
|
||||
@AppScope
|
||||
class AppComponent private constructor(
|
||||
@Component
|
||||
actual abstract class AppComponent constructor(
|
||||
actual val dataComponent: DataComponent = DataComponent.create(),
|
||||
@Component
|
||||
val dataComponent: DataComponent = DataComponent.create(),
|
||||
@Component
|
||||
val uiComponent: UiComponent = UiComponent.create(dataComponent)
|
||||
actual val uiComponent: UiComponent = UiComponent.create(dataComponent)
|
||||
) {
|
||||
actual abstract val contextWrapper: ContextWrapper
|
||||
companion object {
|
||||
private var appComponentInstance: AppComponent? = null
|
||||
|
||||
fun getInstance() = appComponentInstance ?: AppComponent()
|
||||
fun getInstance() = appComponentInstance ?: create()
|
||||
.also { appComponentInstance = it }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.base
|
||||
|
||||
import ca.gosyer.core.di.AppScope
|
||||
import ca.gosyer.data.DataComponent
|
||||
import ca.gosyer.ui.base.image.KamelConfigProvider
|
||||
import ca.gosyer.ui.base.vm.ViewModelFactoryImpl
|
||||
import ca.gosyer.uicore.vm.LocalViewModelFactory
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import io.kamel.image.config.LocalKamelConfig
|
||||
import io.kamel.image.config.resourcesFetcher
|
||||
import me.tatarka.inject.annotations.Component
|
||||
import me.tatarka.inject.annotations.Provides
|
||||
|
||||
@AppScope
|
||||
@Component
|
||||
actual abstract class UiComponent(
|
||||
@Component actual val dataComponent: DataComponent
|
||||
) {
|
||||
protected actual abstract val kamelConfigProvider: KamelConfigProvider
|
||||
|
||||
actual abstract val viewModelFactory: ViewModelFactoryImpl
|
||||
|
||||
actual abstract val kamelConfig: KamelConfig
|
||||
|
||||
@get:AppScope
|
||||
@get:Provides
|
||||
protected actual val kamelConfigFactory: KamelConfig
|
||||
get() = kamelConfigProvider.get { resourcesFetcher() }
|
||||
|
||||
actual fun getHooks() = arrayOf(
|
||||
LocalViewModelFactory provides viewModelFactory,
|
||||
LocalKamelConfig provides kamelConfig
|
||||
)
|
||||
|
||||
actual companion object
|
||||
}
|
||||
@@ -31,6 +31,18 @@ actual fun VerticalScrollbar(
|
||||
adapter, modifier, reverseLayout, style, interactionSource
|
||||
)
|
||||
|
||||
@Composable
|
||||
actual fun HorizontalScrollbar(
|
||||
adapter: ScrollbarAdapter,
|
||||
modifier: Modifier,
|
||||
reverseLayout: Boolean,
|
||||
style: ScrollbarStyle,
|
||||
interactionSource: MutableInteractionSource
|
||||
) = androidx.compose.foundation.HorizontalScrollbar(
|
||||
adapter, modifier, reverseLayout, style, interactionSource
|
||||
)
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
actual fun rememberScrollbarAdapter(
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.base.prefs
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
internal actual fun Color.toHsv(): FloatArray {
|
||||
fun Float.toIntColor() = (this * 256).toInt()
|
||||
val result = floatArrayOf(0f, 0f, 0f)
|
||||
java.awt.Color.RGBtoHSB(red.toIntColor(), green.toIntColor(), blue.toIntColor(), result)
|
||||
return result
|
||||
}
|
||||
|
||||
internal actual fun hexStringToColor(hex: String): Color? {
|
||||
return try {
|
||||
val color = java.awt.Color.decode(hex)
|
||||
Color(color.red, color.green, color.blue, color.alpha)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.categories
|
||||
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.remember
|
||||
import ca.gosyer.presentation.build.BuildKonfig
|
||||
import ca.gosyer.ui.AppComponent
|
||||
import ca.gosyer.ui.util.compose.ThemedWindow
|
||||
import ca.gosyer.ui.util.lang.launchApplication
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun openCategoriesMenu(notifyFinished: (() -> Unit)? = null) {
|
||||
launchApplication {
|
||||
CompositionLocalProvider(*remember { AppComponent.getInstance().uiComponent.getHooks() }) {
|
||||
ThemedWindow(::exitApplication, title = "${BuildKonfig.NAME} - Categories") {
|
||||
Navigator(remember { CategoriesScreen(notifyFinished) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,16 @@
|
||||
package ca.gosyer.ui.main.components
|
||||
|
||||
import ca.gosyer.data.update.UpdateChecker
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
|
||||
class TrayViewModel @Inject constructor(
|
||||
private val updateChecker: UpdateChecker
|
||||
) : ViewModel() {
|
||||
private val updateChecker: UpdateChecker,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
override val scope = MainScope()
|
||||
|
||||
init {
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.reader
|
||||
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.input.key.KeyEvent
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.WindowPlacement
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import ca.gosyer.data.ui.model.WindowSettings
|
||||
import ca.gosyer.presentation.build.BuildKonfig
|
||||
import ca.gosyer.ui.AppComponent
|
||||
import ca.gosyer.ui.base.theme.AppTheme
|
||||
import ca.gosyer.ui.util.compose.WindowGet
|
||||
import ca.gosyer.ui.util.lang.launchApplication
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
actual fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
|
||||
val windowSettings = AppComponent.getInstance().dataComponent.uiPreferences
|
||||
.readerWindow()
|
||||
val (
|
||||
position,
|
||||
size,
|
||||
placement
|
||||
) = WindowGet.from(windowSettings.get())
|
||||
|
||||
val hooks = AppComponent.getInstance().uiComponent.getHooks()
|
||||
|
||||
launchApplication {
|
||||
val scope = rememberCoroutineScope()
|
||||
val hotkeyFlow = remember { MutableSharedFlow<KeyEvent>() }
|
||||
val icon = painterResource("icon.png")
|
||||
val windowState = rememberWindowState(size = size, position = position, placement = placement)
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
windowSettings.set(
|
||||
WindowSettings(
|
||||
windowState.position.x.value.toInt(),
|
||||
windowState.position.y.value.toInt(),
|
||||
windowState.size.width.value.toInt(),
|
||||
windowState.size.height.value.toInt(),
|
||||
windowState.placement == WindowPlacement.Maximized,
|
||||
windowState.placement == WindowPlacement.Fullscreen
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "${BuildKonfig.NAME} - Reader",
|
||||
icon = icon,
|
||||
state = windowState,
|
||||
onKeyEvent = {
|
||||
if (it.type != KeyEventType.KeyDown) return@Window false
|
||||
scope.launch {
|
||||
hotkeyFlow.emit(it)
|
||||
}
|
||||
it.key in supportedKeyList
|
||||
}
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
*hooks
|
||||
) {
|
||||
AppTheme {
|
||||
ReaderMenu(chapterIndex, mangaId, hotkeyFlow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import ca.gosyer.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.uicore.prefs.asStateIn
|
||||
import ca.gosyer.uicore.prefs.asStringStateIn
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -98,8 +99,9 @@ class SettingsServerScreen : Screen {
|
||||
}
|
||||
|
||||
class SettingsServerViewModel @Inject constructor(
|
||||
serverPreferences: ServerPreferences
|
||||
) : ViewModel() {
|
||||
serverPreferences: ServerPreferences,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
val serverUrl = serverPreferences.server().asStateIn(scope)
|
||||
val serverPort = serverPreferences.port().asStringStateIn(scope)
|
||||
|
||||
@@ -140,8 +142,9 @@ class SettingsServerViewModel @Inject constructor(
|
||||
class SettingsServerHostViewModel @Inject constructor(
|
||||
serverPreferences: ServerPreferences,
|
||||
serverHostPreferences: ServerHostPreferences,
|
||||
private val serverService: ServerService
|
||||
) : ViewModel() {
|
||||
private val serverService: ServerService,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
val host = serverHostPreferences.host().asStateIn(scope)
|
||||
val ip = serverHostPreferences.ip().asStateIn(scope)
|
||||
val port = serverHostPreferences.port().asStringStateIn(scope)
|
||||
|
||||
@@ -28,7 +28,7 @@ suspend fun imageFromUrl(client: Http, url: String, block: HttpRequestBuilder.()
|
||||
return client.get<ByteReadChannel>(url, block).toImageBitmap()
|
||||
}
|
||||
|
||||
suspend fun ByteReadChannel.toImageBitmap(): ImageBitmap {
|
||||
actual suspend fun ByteReadChannel.toImageBitmap(): ImageBitmap {
|
||||
val bytes = ByteArrayOutputStream().use {
|
||||
this.copyTo(it)
|
||||
it.toByteArray()
|
||||
|
||||
@@ -8,28 +8,27 @@ package ca.gosyer.ui.util.system
|
||||
|
||||
import ca.gosyer.core.lang.launchUI
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import okio.Path
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import javax.swing.JFileChooser
|
||||
import javax.swing.filechooser.FileNameExtensionFilter
|
||||
import kotlin.io.path.Path
|
||||
|
||||
fun filePicker(
|
||||
vararg extensions: String,
|
||||
builder: JFileChooser.() -> Unit = {},
|
||||
onCancel: (JFileChooser) -> Unit = {},
|
||||
onError: (JFileChooser) -> Unit = {},
|
||||
onApprove: (JFileChooser) -> Unit
|
||||
) = fileChooser(false, builder, onCancel, onError, onApprove, extensions = extensions)
|
||||
onCancel: () -> Unit = {},
|
||||
onError: () -> Unit = {},
|
||||
onApprove: (Path) -> Unit
|
||||
) = fileChooser(false, onCancel, onError, onApprove, extensions = extensions)
|
||||
|
||||
fun fileSaver(
|
||||
defaultFileName: String,
|
||||
extension: String,
|
||||
builder: JFileChooser.() -> Unit = {},
|
||||
onCancel: (JFileChooser) -> Unit = {},
|
||||
onError: (JFileChooser) -> Unit = {},
|
||||
onApprove: (JFileChooser) -> Unit
|
||||
onCancel: () -> Unit = {},
|
||||
onError: () -> Unit = {},
|
||||
onApprove: (Path) -> Unit
|
||||
) = fileChooser(
|
||||
true,
|
||||
builder,
|
||||
onCancel,
|
||||
onError,
|
||||
onApprove,
|
||||
@@ -41,18 +40,16 @@ fun fileSaver(
|
||||
* Opens a swing file picker, in the details view by default
|
||||
*
|
||||
* @param saving true if the dialog is going to save a file, false if its going to open a file
|
||||
* @param builder invokes this builder before launching the file picker, such as adding a action listener
|
||||
* @param onCancel the listener that is called when picking a file is canceled
|
||||
* @param onError the listener that is called when picking a file exited with a error
|
||||
* @param onApprove the listener that is called when picking a file is completed
|
||||
*/
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
private fun fileChooser(
|
||||
internal fun fileChooser(
|
||||
saving: Boolean = false,
|
||||
builder: JFileChooser.() -> Unit = {},
|
||||
onCancel: (JFileChooser) -> Unit = {},
|
||||
onError: (JFileChooser) -> Unit = {},
|
||||
onApprove: (JFileChooser) -> Unit,
|
||||
onCancel: () -> Unit = {},
|
||||
onError: () -> Unit = {},
|
||||
onApprove: (Path) -> Unit,
|
||||
defaultFileName: String = "",
|
||||
vararg extensions: String,
|
||||
) = launchUI {
|
||||
@@ -67,7 +64,6 @@ private fun fileChooser(
|
||||
selectedFile = Path(defaultFileName).toFile()
|
||||
}
|
||||
}
|
||||
.apply(builder)
|
||||
|
||||
val result = fileChooser.let {
|
||||
if (saving) {
|
||||
@@ -78,8 +74,8 @@ private fun fileChooser(
|
||||
}
|
||||
|
||||
when (result) {
|
||||
JFileChooser.APPROVE_OPTION -> onApprove(fileChooser)
|
||||
JFileChooser.CANCEL_OPTION -> onCancel(fileChooser)
|
||||
JFileChooser.ERROR_OPTION -> onError(fileChooser)
|
||||
JFileChooser.APPROVE_OPTION -> onApprove(fileChooser.selectedFile.toOkioPath())
|
||||
JFileChooser.CANCEL_OPTION -> onCancel()
|
||||
JFileChooser.ERROR_OPTION -> onError()
|
||||
}
|
||||
}
|
||||
|
||||
18
presentation/src/jvmMain/kotlin/ca/gosyer/ui/AppComponent.kt
Normal file
18
presentation/src/jvmMain/kotlin/ca/gosyer/ui/AppComponent.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui
|
||||
|
||||
import ca.gosyer.data.DataComponent
|
||||
import ca.gosyer.ui.base.UiComponent
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
|
||||
expect abstract class AppComponent {
|
||||
val dataComponent: DataComponent
|
||||
val uiComponent: UiComponent
|
||||
|
||||
abstract val contextWrapper: ContextWrapper
|
||||
}
|
||||
@@ -6,36 +6,23 @@
|
||||
|
||||
package ca.gosyer.ui.base
|
||||
|
||||
import ca.gosyer.core.di.AppScope
|
||||
import androidx.compose.runtime.ProvidedValue
|
||||
import ca.gosyer.data.DataComponent
|
||||
import ca.gosyer.ui.base.image.KamelConfigProvider
|
||||
import ca.gosyer.ui.base.vm.ViewModelFactoryImpl
|
||||
import ca.gosyer.uicore.vm.LocalViewModelFactory
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import io.kamel.image.config.LocalKamelConfig
|
||||
import me.tatarka.inject.annotations.Component
|
||||
import me.tatarka.inject.annotations.Provides
|
||||
|
||||
@AppScope
|
||||
@Component
|
||||
abstract class UiComponent(
|
||||
@Component protected val dataComponent: DataComponent
|
||||
) {
|
||||
expect abstract class UiComponent {
|
||||
protected val dataComponent: DataComponent
|
||||
protected abstract val kamelConfigProvider: KamelConfigProvider
|
||||
|
||||
abstract val viewModelFactory: ViewModelFactoryImpl
|
||||
|
||||
abstract val kamelConfig: KamelConfig
|
||||
|
||||
@get:AppScope
|
||||
@get:Provides
|
||||
protected val kamelConfigFactory: KamelConfig
|
||||
get() = kamelConfigProvider.get()
|
||||
|
||||
fun getHooks() = arrayOf(
|
||||
LocalViewModelFactory provides viewModelFactory,
|
||||
LocalKamelConfig provides kamelConfig
|
||||
)
|
||||
fun getHooks(): Array<ProvidedValue<out Any>>
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ca.gosyer.ui.base.components
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun VerticalScrollbar(
|
||||
adapter: ScrollbarAdapter,
|
||||
modifier: Modifier = Modifier,
|
||||
reverseLayout: Boolean = false,
|
||||
style: ScrollbarStyle = LocalScrollbarStyle.current,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
real: Boolean = false
|
||||
) = VerticalScrollbar(adapter, modifier, reverseLayout, style, interactionSource)
|
||||
@@ -11,6 +11,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
expect interface ScrollbarAdapter
|
||||
@@ -28,6 +29,34 @@ expect fun VerticalScrollbar(
|
||||
interactionSource: MutableInteractionSource,
|
||||
)
|
||||
|
||||
@Composable
|
||||
expect fun HorizontalScrollbar(
|
||||
adapter: ScrollbarAdapter,
|
||||
modifier: Modifier,
|
||||
reverseLayout: Boolean,
|
||||
style: ScrollbarStyle,
|
||||
interactionSource: MutableInteractionSource,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun VerticalScrollbar(
|
||||
adapter: ScrollbarAdapter,
|
||||
modifier: Modifier = Modifier,
|
||||
reverseLayout: Boolean = false,
|
||||
style: ScrollbarStyle = LocalScrollbarStyle.current,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
real: Boolean = false
|
||||
) = VerticalScrollbar(adapter, modifier, reverseLayout, style, interactionSource)
|
||||
|
||||
@Composable
|
||||
fun HorizontalScrollbar(
|
||||
adapter: ScrollbarAdapter,
|
||||
modifier: Modifier = Modifier,
|
||||
reverseLayout: Boolean = false,
|
||||
style: ScrollbarStyle = LocalScrollbarStyle.current,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
real: Boolean = false
|
||||
) = HorizontalScrollbar(adapter, modifier, reverseLayout, style, interactionSource)
|
||||
|
||||
@Composable
|
||||
expect fun rememberScrollbarAdapter(
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
package ca.gosyer.ui.base.dialog
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.toPainter
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.presentation.build.BuildKonfig
|
||||
import ca.gosyer.uicore.resources.toPainter
|
||||
import com.vanpra.composematerialdialogs.DesktopWindowPosition
|
||||
import com.vanpra.composematerialdialogs.MaterialDialogProperties
|
||||
import com.vanpra.composematerialdialogs.SecurePolicy
|
||||
@@ -28,7 +27,7 @@ fun getMaterialDialogProperties(
|
||||
position: DesktopWindowPosition = DesktopWindowPosition(Alignment.Center),
|
||||
size: DpSize = DpSize(400.dp, 300.dp),
|
||||
title: String = BuildKonfig.NAME,
|
||||
icon: Painter = remember { MR.images.icon.image.toPainter() },
|
||||
icon: Painter = MR.images.icon.toPainter(),
|
||||
resizable: Boolean = true
|
||||
): MaterialDialogProperties {
|
||||
return MaterialDialogProperties(
|
||||
|
||||
@@ -14,6 +14,7 @@ import ca.gosyer.data.server.ServerPreferences
|
||||
import ca.gosyer.uicore.prefs.asStateIn
|
||||
import io.kamel.core.config.DefaultCacheSize
|
||||
import io.kamel.core.config.KamelConfig
|
||||
import io.kamel.core.config.KamelConfigBuilder
|
||||
import io.kamel.core.config.fileFetcher
|
||||
import io.kamel.core.config.httpFetcher
|
||||
import io.kamel.core.config.stringMapper
|
||||
@@ -21,7 +22,6 @@ import io.kamel.core.config.uriMapper
|
||||
import io.kamel.core.config.urlMapper
|
||||
import io.kamel.core.mapper.Mapper
|
||||
import io.kamel.image.config.imageBitmapDecoder
|
||||
import io.kamel.image.config.resourcesFetcher
|
||||
import io.ktor.http.Url
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -36,7 +36,7 @@ class KamelConfigProvider @Inject constructor(
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
val serverUrl = serverPreferences.serverUrl().asStateIn(GlobalScope)
|
||||
|
||||
fun get(): KamelConfig {
|
||||
fun get(resourcesFetcher: KamelConfigBuilder.() -> Unit): KamelConfig {
|
||||
return KamelConfig {
|
||||
// Default config
|
||||
imageBitmapCacheSize = DefaultCacheSize
|
||||
|
||||
@@ -416,12 +416,7 @@ fun hsvToColor(hue: Float, saturation: Float, value: Float): Color {
|
||||
return Color.hsv(hue, saturation, value)
|
||||
}
|
||||
|
||||
private fun Color.toHsv(): FloatArray {
|
||||
fun Float.toIntColor() = (this * 256).toInt()
|
||||
val result = floatArrayOf(0f, 0f, 0f)
|
||||
java.awt.Color.RGBtoHSB(red.toIntColor(), green.toIntColor(), blue.toIntColor(), result)
|
||||
return result
|
||||
}
|
||||
internal expect fun Color.toHsv(): FloatArray
|
||||
|
||||
private fun hueToColor(hue: Float): Color {
|
||||
return hsvToColor(hue, 1f, 1f)
|
||||
@@ -431,14 +426,7 @@ private fun Color.toHexString(): String {
|
||||
return String.format("#%06X", (0xFFFFFF and toArgb()))
|
||||
}
|
||||
|
||||
private fun hexStringToColor(hex: String): Color? {
|
||||
return try {
|
||||
val color = java.awt.Color.decode(hex)
|
||||
Color(color.red, color.green, color.blue, color.alpha)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
internal expect fun hexStringToColor(hex: String): Color?
|
||||
|
||||
private val presetColors = listOf(
|
||||
Color(0xFFF44336), // RED 500
|
||||
|
||||
@@ -25,6 +25,7 @@ import ca.gosyer.ui.base.components.LocalScrollbarStyle
|
||||
import ca.gosyer.ui.base.theme.ThemeScrollbarStyle.getScrollbarStyle
|
||||
import ca.gosyer.uicore.theme.Theme
|
||||
import ca.gosyer.uicore.theme.themes
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.LocalViewModelFactory
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -54,8 +55,9 @@ fun AppTheme(content: @Composable () -> Unit) {
|
||||
}
|
||||
|
||||
class AppThemeViewModel @Inject constructor(
|
||||
private val uiPreferences: UiPreferences
|
||||
) : ViewModel() {
|
||||
private val uiPreferences: UiPreferences,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
override val scope = MainScope()
|
||||
|
||||
private val themeMode = uiPreferences.themeMode().asStateFlow()
|
||||
|
||||
@@ -7,31 +7,12 @@
|
||||
package ca.gosyer.ui.categories
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import ca.gosyer.presentation.build.BuildKonfig
|
||||
import ca.gosyer.ui.AppComponent
|
||||
import ca.gosyer.ui.categories.components.CategoriesScreenContent
|
||||
import ca.gosyer.ui.util.compose.ThemedWindow
|
||||
import ca.gosyer.ui.util.lang.launchApplication
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.core.screen.ScreenKey
|
||||
import cafe.adriel.voyager.core.screen.uniqueScreenKey
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun openCategoriesMenu(notifyFinished: (() -> Unit)? = null) {
|
||||
launchApplication {
|
||||
CompositionLocalProvider(*remember { AppComponent.getInstance().uiComponent.getHooks() }) {
|
||||
ThemedWindow(::exitApplication, title = "${BuildKonfig.NAME} - Categories") {
|
||||
Navigator(remember { CategoriesScreen(notifyFinished) })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CategoriesScreen(
|
||||
@Transient
|
||||
@@ -10,6 +10,7 @@ import ca.gosyer.core.lang.throwIfCancellation
|
||||
import ca.gosyer.core.logging.CKLogger
|
||||
import ca.gosyer.data.models.Category
|
||||
import ca.gosyer.data.server.interactions.CategoryInteractionHandler
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -17,8 +18,9 @@ import kotlinx.coroutines.launch
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
|
||||
class CategoriesScreenViewModel @Inject constructor(
|
||||
private val categoryHandler: CategoryInteractionHandler
|
||||
) : ViewModel() {
|
||||
private val categoryHandler: CategoryInteractionHandler,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
private var originalCategories = emptyList<Category>()
|
||||
private val _categories = MutableStateFlow(emptyList<MenuCategory>())
|
||||
val categories = _categories.asStateFlow()
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.categories.components
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -19,7 +19,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.ExtendedFloatingActionButton
|
||||
@@ -10,6 +10,7 @@ import ca.gosyer.data.download.DownloadService
|
||||
import ca.gosyer.data.models.Chapter
|
||||
import ca.gosyer.data.server.interactions.ChapterInteractionHandler
|
||||
import ca.gosyer.data.server.interactions.DownloadInteractionHandler
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.MainScope
|
||||
@@ -20,8 +21,9 @@ class DownloadsScreenViewModel @Inject constructor(
|
||||
private val downloadService: DownloadService,
|
||||
private val downloadsHandler: DownloadInteractionHandler,
|
||||
private val chapterHandler: ChapterInteractionHandler,
|
||||
contextWrapper: ContextWrapper,
|
||||
standalone: Boolean
|
||||
) : ViewModel() {
|
||||
) : ViewModel(contextWrapper) {
|
||||
private val uiScope = if (standalone) {
|
||||
MainScope()
|
||||
} else null
|
||||
@@ -7,7 +7,7 @@
|
||||
package ca.gosyer.ui.downloads.components
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
@@ -21,7 +21,7 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
@@ -12,6 +12,7 @@ import ca.gosyer.data.extension.ExtensionPreferences
|
||||
import ca.gosyer.data.models.Extension
|
||||
import ca.gosyer.data.server.interactions.ExtensionInteractionHandler
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
@@ -26,8 +27,9 @@ import java.util.Locale
|
||||
|
||||
class ExtensionsScreenViewModel @Inject constructor(
|
||||
private val extensionHandler: ExtensionInteractionHandler,
|
||||
extensionPreferences: ExtensionPreferences
|
||||
) : ViewModel() {
|
||||
extensionPreferences: ExtensionPreferences,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
private val extensionList = MutableStateFlow<List<Extension>?>(null)
|
||||
|
||||
private val _enabledLangs = extensionPreferences.languages().asStateFlow()
|
||||
@@ -137,10 +139,10 @@ class ExtensionsScreenViewModel @Inject constructor(
|
||||
val available = filter { !it.installed }.sortedWith(comparator)
|
||||
|
||||
return mapOf(
|
||||
MR.strings.installed.localized() to (obsolete + updates + installed),
|
||||
MR.strings.installed.toPlatformString() to (obsolete + updates + installed),
|
||||
).filterNot { it.value.isEmpty() } + available.groupBy { it.lang }.mapKeys {
|
||||
if (it.key == "all") {
|
||||
MR.strings.all.localized()
|
||||
MR.strings.all.toPlatformString()
|
||||
} else {
|
||||
Locale.forLanguageTag(it.key).displayName
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.extensions.components
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -24,7 +24,7 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.MaterialTheme
|
||||
@@ -14,6 +14,7 @@ import ca.gosyer.data.models.Manga
|
||||
import ca.gosyer.data.server.interactions.CategoryInteractionHandler
|
||||
import ca.gosyer.data.server.interactions.LibraryInteractionHandler
|
||||
import ca.gosyer.data.server.interactions.UpdatesInteractionHandler
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
@@ -71,8 +72,9 @@ class LibraryScreenViewModel @Inject constructor(
|
||||
private val categoryHandler: CategoryInteractionHandler,
|
||||
private val libraryHandler: LibraryInteractionHandler,
|
||||
private val updatesHandler: UpdatesInteractionHandler,
|
||||
libraryPreferences: LibraryPreferences
|
||||
) : ViewModel() {
|
||||
libraryPreferences: LibraryPreferences,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
private val library = Library(MutableStateFlow(emptyList()), mutableMapOf())
|
||||
val categories = library.categories.asStateFlow()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package ca.gosyer.ui.library.components
|
||||
|
||||
import androidx.compose.foundation.ContextMenuItem
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
@@ -18,7 +18,7 @@ import androidx.compose.foundation.lazy.GridCells
|
||||
import androidx.compose.foundation.lazy.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.LocalTextStyle
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
@@ -7,14 +7,22 @@
|
||||
package ca.gosyer.ui.main
|
||||
|
||||
import ca.gosyer.data.ui.UiPreferences
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
|
||||
class MainViewModel @Inject constructor(
|
||||
uiPreferences: UiPreferences
|
||||
) : ViewModel() {
|
||||
uiPreferences: UiPreferences,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
override val scope = MainScope()
|
||||
|
||||
val startScreen = uiPreferences.startScreen().get()
|
||||
|
||||
override fun onDispose() {
|
||||
super.onDispose()
|
||||
scope.cancel()
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.main.components
|
||||
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -14,7 +15,7 @@ import kotlinx.coroutines.launch
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
class DebugOverlayViewModel @Inject constructor() : ViewModel() {
|
||||
class DebugOverlayViewModel @Inject constructor(contextWrapper: ContextWrapper) : ViewModel(contextWrapper) {
|
||||
override val scope = MainScope()
|
||||
|
||||
val runtime: Runtime = Runtime.getRuntime()
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
package ca.gosyer.ui.main.more.components
|
||||
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -26,13 +25,13 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.ui.main.MoreMenus
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.resources.toPainter
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
|
||||
@Composable
|
||||
@@ -46,7 +45,7 @@ fun MoreContent() {
|
||||
item {
|
||||
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
|
||||
Image(
|
||||
painter = painterResource("icon.png"),
|
||||
painter = MR.images.icon.toPainter(),
|
||||
contentDescription = "icon",
|
||||
modifier = Modifier.height(140.dp).padding(vertical = 8.dp)
|
||||
)
|
||||
@@ -86,8 +85,10 @@ fun MoreContent() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Preview
|
||||
@Composable
|
||||
private fun MorePreview() {
|
||||
MoreContent()
|
||||
}
|
||||
*/
|
||||
@@ -18,6 +18,7 @@ import ca.gosyer.data.server.interactions.LibraryInteractionHandler
|
||||
import ca.gosyer.data.server.interactions.MangaInteractionHandler
|
||||
import ca.gosyer.data.ui.UiPreferences
|
||||
import ca.gosyer.ui.base.chapter.ChapterDownloadItem
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
@@ -42,8 +43,9 @@ class MangaScreenViewModel @Inject constructor(
|
||||
private val libraryHandler: LibraryInteractionHandler,
|
||||
private val downloadService: DownloadService,
|
||||
uiPreferences: UiPreferences,
|
||||
contextWrapper: ContextWrapper,
|
||||
private val params: Params,
|
||||
) : ViewModel() {
|
||||
) : ViewModel(contextWrapper) {
|
||||
private val downloadingChapters = downloadService.registerWatch(params.mangaId)
|
||||
|
||||
private val _manga = MutableStateFlow<Manga?>(null)
|
||||
@@ -115,9 +117,8 @@ class MangaScreenViewModel @Inject constructor(
|
||||
|
||||
fun setCategories() {
|
||||
scope.launch {
|
||||
manga.value?.let { manga ->
|
||||
chooseCategoriesFlow.emit(Unit)
|
||||
}
|
||||
manga.value ?: return@launch
|
||||
chooseCategoriesFlow.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.manga.components
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -23,7 +23,7 @@ import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.material.Card
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.manga.components
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -15,7 +15,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Favorite
|
||||
@@ -29,14 +29,12 @@ import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ChevronRight
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -44,23 +42,13 @@ import androidx.compose.ui.graphics.FilterQuality
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.KeyEvent
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.WindowPlacement
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import ca.gosyer.data.reader.model.Direction
|
||||
import ca.gosyer.data.reader.model.ImageScale
|
||||
import ca.gosyer.data.reader.model.NavigationMode
|
||||
import ca.gosyer.data.ui.model.WindowSettings
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.presentation.build.BuildKonfig
|
||||
import ca.gosyer.ui.AppComponent
|
||||
import ca.gosyer.ui.base.theme.AppTheme
|
||||
import ca.gosyer.ui.reader.model.Navigation
|
||||
import ca.gosyer.ui.reader.model.ReaderChapter
|
||||
import ca.gosyer.ui.reader.model.ReaderPage
|
||||
@@ -71,18 +59,13 @@ import ca.gosyer.ui.reader.navigation.RightAndLeftNavigation
|
||||
import ca.gosyer.ui.reader.navigation.navigationClickable
|
||||
import ca.gosyer.ui.reader.viewer.ContinuousReader
|
||||
import ca.gosyer.ui.reader.viewer.PagerReader
|
||||
import ca.gosyer.ui.util.compose.WindowGet
|
||||
import ca.gosyer.ui.util.lang.launchApplication
|
||||
import ca.gosyer.uicore.components.ErrorScreen
|
||||
import ca.gosyer.uicore.components.LoadingScreen
|
||||
import ca.gosyer.uicore.components.mangaAspectRatio
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.LocalViewModelFactory
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
val supportedKeyList = listOf(
|
||||
Key.W,
|
||||
@@ -95,60 +78,7 @@ val supportedKeyList = listOf(
|
||||
Key.DirectionRight
|
||||
)
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
|
||||
val windowSettings = AppComponent.getInstance().dataComponent.uiPreferences
|
||||
.readerWindow()
|
||||
val (
|
||||
position,
|
||||
size,
|
||||
placement
|
||||
) = WindowGet.from(windowSettings.get())
|
||||
|
||||
val hooks = AppComponent.getInstance().uiComponent.getHooks()
|
||||
|
||||
launchApplication {
|
||||
val scope = rememberCoroutineScope()
|
||||
val hotkeyFlow = remember { MutableSharedFlow<KeyEvent>() }
|
||||
val icon = painterResource("icon.png")
|
||||
val windowState = rememberWindowState(size = size, position = position, placement = placement)
|
||||
DisposableEffect(Unit) {
|
||||
onDispose {
|
||||
windowSettings.set(
|
||||
WindowSettings(
|
||||
windowState.position.x.value.toInt(),
|
||||
windowState.position.y.value.toInt(),
|
||||
windowState.size.width.value.toInt(),
|
||||
windowState.size.height.value.toInt(),
|
||||
windowState.placement == WindowPlacement.Maximized,
|
||||
windowState.placement == WindowPlacement.Fullscreen
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "${BuildKonfig.NAME} - Reader",
|
||||
icon = icon,
|
||||
state = windowState,
|
||||
onKeyEvent = {
|
||||
if (it.type != KeyEventType.KeyDown) return@Window false
|
||||
scope.launch {
|
||||
hotkeyFlow.emit(it)
|
||||
}
|
||||
it.key in supportedKeyList
|
||||
}
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
*hooks
|
||||
) {
|
||||
AppTheme {
|
||||
ReaderMenu(chapterIndex, mangaId, hotkeyFlow)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
expect fun openReaderMenu(chapterIndex: Int, mangaId: Long)
|
||||
|
||||
@Composable
|
||||
fun ReaderMenu(
|
||||
@@ -24,6 +24,7 @@ import ca.gosyer.ui.reader.model.ReaderChapter
|
||||
import ca.gosyer.ui.reader.model.ReaderPage
|
||||
import ca.gosyer.ui.reader.model.ViewerChapters
|
||||
import ca.gosyer.uicore.prefs.asStateIn
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -45,8 +46,9 @@ class ReaderMenuViewModel @Inject constructor(
|
||||
private val readerPreferences: ReaderPreferences,
|
||||
private val mangaHandler: MangaInteractionHandler,
|
||||
private val chapterHandler: ChapterInteractionHandler,
|
||||
contextWrapper: ContextWrapper,
|
||||
private val params: Params,
|
||||
) : ViewModel() {
|
||||
) : ViewModel(contextWrapper) {
|
||||
private val _manga = MutableStateFlow<Manga?>(null)
|
||||
private val viewerChapters = ViewerChapters(
|
||||
MutableStateFlow(null),
|
||||
@@ -7,7 +7,6 @@
|
||||
package ca.gosyer.ui.reader
|
||||
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -41,15 +40,12 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import ca.gosyer.core.logging.kLogger
|
||||
import ca.gosyer.core.util.replace
|
||||
import ca.gosyer.data.models.Chapter
|
||||
import ca.gosyer.data.models.ChapterMeta
|
||||
import ca.gosyer.data.models.MangaMeta
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.ui.reader.model.ReaderChapter
|
||||
import ca.gosyer.uicore.components.Spinner
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
private val logger = kLogger {}
|
||||
|
||||
@@ -160,7 +156,7 @@ private fun NavigateChapters(loadPrevChapter: () -> Unit, loadNextChapter: () ->
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
/*@Preview
|
||||
@Composable
|
||||
private fun ReaderSideMenuPreview() {
|
||||
ReaderSideMenu(
|
||||
@@ -195,4 +191,4 @@ private fun ReaderSideMenuPreview() {
|
||||
onPrevChapterClicked = {},
|
||||
onNextChapterClicked = {}
|
||||
)
|
||||
}
|
||||
}*/
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
package ca.gosyer.ui.reader.viewer
|
||||
|
||||
import androidx.compose.foundation.HorizontalScrollbar
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import androidx.compose.foundation.gestures.animateScrollBy
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
@@ -23,7 +21,6 @@ import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -33,6 +30,9 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ca.gosyer.data.reader.model.Direction
|
||||
import ca.gosyer.ui.base.components.HorizontalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.reader.ChapterSeparator
|
||||
import ca.gosyer.ui.reader.ReaderImage
|
||||
import ca.gosyer.ui.reader.model.MoveTo
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -25,6 +25,7 @@ import ca.gosyer.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||
import ca.gosyer.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -46,7 +47,8 @@ class SettingsAdvancedScreen : Screen {
|
||||
|
||||
class SettingsAdvancedViewModel @Inject constructor(
|
||||
updatePreferences: UpdatePreferences,
|
||||
) : ViewModel() {
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
val updatesEnabled = updatePreferences.enabled().asStateFlow()
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -20,7 +20,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
@@ -50,6 +50,7 @@ import ca.gosyer.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.theme.Theme
|
||||
import ca.gosyer.uicore.theme.themes
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -75,7 +76,8 @@ class SettingsAppearanceScreen : Screen {
|
||||
|
||||
class ThemesViewModel @Inject constructor(
|
||||
private val uiPreferences: UiPreferences,
|
||||
) : ViewModel() {
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
|
||||
val themeMode = uiPreferences.themeMode().asStateFlow()
|
||||
val lightTheme = uiPreferences.lightTheme().asStateFlow()
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -15,7 +14,6 @@ import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
@@ -40,12 +38,15 @@ import ca.gosyer.core.lang.throwIfCancellation
|
||||
import ca.gosyer.core.logging.CKLogger
|
||||
import ca.gosyer.data.server.interactions.BackupInteractionHandler
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.dialog.getMaterialDialogProperties
|
||||
import ca.gosyer.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.ui.base.prefs.PreferenceRow
|
||||
import ca.gosyer.ui.util.system.filePicker
|
||||
import ca.gosyer.ui.util.system.fileSaver
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -68,7 +69,6 @@ import kotlinx.coroutines.launch
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
import okio.FileSystem
|
||||
import okio.Path
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
|
||||
@@ -96,8 +96,9 @@ class SettingsBackupScreen : Screen {
|
||||
}
|
||||
|
||||
class SettingsBackupViewModel @Inject constructor(
|
||||
private val backupHandler: BackupInteractionHandler
|
||||
) : ViewModel() {
|
||||
private val backupHandler: BackupInteractionHandler,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
private val _restoring = MutableStateFlow(false)
|
||||
val restoring = _restoring.asStateFlow()
|
||||
private val _restoringProgress = MutableStateFlow<Float?>(null)
|
||||
@@ -246,9 +247,7 @@ private fun SettingsBackupScreenContent(
|
||||
}
|
||||
launch {
|
||||
createFlow.collect { (filename, function) ->
|
||||
fileSaver(filename, "proto.gz") {
|
||||
function(it.selectedFile.toOkioPath())
|
||||
}
|
||||
fileSaver(filename, "proto.gz", onApprove = function)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,9 +268,7 @@ private fun SettingsBackupScreenContent(
|
||||
restoringProgress,
|
||||
restoreStatus
|
||||
) {
|
||||
filePicker("gz") {
|
||||
restoreFile(it.selectedFile.toOkioPath())
|
||||
}
|
||||
filePicker("gz", onApprove = restoreFile)
|
||||
}
|
||||
PreferenceFile(
|
||||
stringResource(MR.strings.backup_create),
|
||||
@@ -6,20 +6,20 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -6,14 +6,12 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -23,11 +21,14 @@ import androidx.compose.ui.unit.dp
|
||||
import ca.gosyer.data.ui.UiPreferences
|
||||
import ca.gosyer.data.ui.model.StartScreen
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.ui.base.prefs.ChoicePreference
|
||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||
import ca.gosyer.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -62,7 +63,8 @@ class SettingsGeneralScreen : Screen {
|
||||
|
||||
class SettingsGeneralViewModel @Inject constructor(
|
||||
uiPreferences: UiPreferences,
|
||||
) : ViewModel() {
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
|
||||
val startScreen = uiPreferences.startScreen().asStateFlow()
|
||||
val confirmExit = uiPreferences.confirmExit().asStateFlow()
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -29,6 +29,7 @@ import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||
import ca.gosyer.ui.categories.openCategoriesMenu
|
||||
import ca.gosyer.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -55,8 +56,9 @@ class SettingsLibraryScreen : Screen {
|
||||
|
||||
class SettingsLibraryViewModel @Inject constructor(
|
||||
libraryPreferences: LibraryPreferences,
|
||||
private val categoryHandler: CategoryInteractionHandler
|
||||
) : ViewModel() {
|
||||
private val categoryHandler: CategoryInteractionHandler,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
|
||||
val showAllCategory = libraryPreferences.showAllCategory().asStateFlow()
|
||||
private val _categories = MutableStateFlow(0)
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -6,14 +6,12 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -29,6 +27,8 @@ import ca.gosyer.data.reader.model.Direction
|
||||
import ca.gosyer.data.reader.model.ImageScale
|
||||
import ca.gosyer.data.reader.model.NavigationMode
|
||||
import ca.gosyer.i18n.MR
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.navigation.Toolbar
|
||||
import ca.gosyer.ui.base.prefs.ChoicePreference
|
||||
import ca.gosyer.ui.base.prefs.ExpandablePreference
|
||||
@@ -36,6 +36,7 @@ import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||
import ca.gosyer.uicore.prefs.PreferenceMutableStateFlow
|
||||
import ca.gosyer.uicore.prefs.asStateIn
|
||||
import ca.gosyer.uicore.resources.stringResource
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import ca.gosyer.uicore.vm.viewModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
@@ -68,8 +69,9 @@ class SettingsReaderScreen : Screen {
|
||||
}
|
||||
|
||||
class SettingsReaderViewModel @Inject constructor(
|
||||
readerPreferences: ReaderPreferences
|
||||
) : ViewModel() {
|
||||
readerPreferences: ReaderPreferences,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
val modes = readerPreferences.modes().asStateFlow()
|
||||
val selectedMode = readerPreferences.mode().asStateIn(scope)
|
||||
|
||||
@@ -88,10 +90,10 @@ class SettingsReaderViewModel @Inject constructor(
|
||||
}.launchIn(scope)
|
||||
}
|
||||
|
||||
fun getDirectionChoices() = Direction.values().associateWith { it.res.localized() }
|
||||
fun getDirectionChoices() = Direction.values().associateWith { it.res.toPlatformString() }
|
||||
|
||||
fun getPaddingChoices() = mapOf(
|
||||
0 to MR.strings.page_padding_none.localized(),
|
||||
0 to MR.strings.page_padding_none.toPlatformString(),
|
||||
8 to "8 Dp",
|
||||
16 to "16 Dp",
|
||||
32 to "32 Dp"
|
||||
@@ -99,23 +101,23 @@ class SettingsReaderViewModel @Inject constructor(
|
||||
|
||||
fun getMaxSizeChoices(direction: Direction) = if (direction == Direction.Right || direction == Direction.Left) {
|
||||
mapOf(
|
||||
0 to MR.strings.max_size_unrestricted.localized(),
|
||||
0 to MR.strings.max_size_unrestricted.toPlatformString(),
|
||||
700 to "700 Dp",
|
||||
900 to "900 Dp",
|
||||
1100 to "1100 Dp"
|
||||
)
|
||||
} else {
|
||||
mapOf(
|
||||
0 to MR.strings.max_size_unrestricted.localized(),
|
||||
0 to MR.strings.max_size_unrestricted.toPlatformString(),
|
||||
500 to "500 Dp",
|
||||
700 to "700 Dp",
|
||||
900 to "900 Dp"
|
||||
)
|
||||
}
|
||||
|
||||
fun getImageScaleChoices() = ImageScale.values().associateWith { it.res.localized() }
|
||||
fun getImageScaleChoices() = ImageScale.values().associateWith { it.res.toPlatformString() }
|
||||
|
||||
fun getNavigationModeChoices() = NavigationMode.values().associateWith { it.res.localized() }
|
||||
fun getNavigationModeChoices() = NavigationMode.values().associateWith { it.res.toPlatformString() }
|
||||
}
|
||||
|
||||
data class ReaderModePreference(
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Backup
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
package ca.gosyer.ui.settings
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -7,12 +7,13 @@
|
||||
package ca.gosyer.ui.sources
|
||||
|
||||
import ca.gosyer.data.models.Source
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import me.tatarka.inject.annotations.Inject
|
||||
|
||||
class SourcesScreenViewModel @Inject constructor() : ViewModel() {
|
||||
class SourcesScreenViewModel @Inject constructor(contextWrapper: ContextWrapper) : ViewModel(contextWrapper) {
|
||||
private val _sourceTabs = MutableStateFlow<List<Source?>>(listOf(null))
|
||||
val sourceTabs = _sourceTabs.asStateFlow()
|
||||
|
||||
@@ -11,6 +11,7 @@ import ca.gosyer.data.models.Manga
|
||||
import ca.gosyer.data.models.MangaPage
|
||||
import ca.gosyer.data.models.Source
|
||||
import ca.gosyer.data.server.interactions.SourceInteractionHandler
|
||||
import ca.gosyer.uicore.vm.ContextWrapper
|
||||
import ca.gosyer.uicore.vm.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
@@ -19,15 +20,18 @@ import me.tatarka.inject.annotations.Inject
|
||||
|
||||
class SourceScreenViewModel(
|
||||
private val source: Source,
|
||||
private val sourceHandler: SourceInteractionHandler
|
||||
) : ViewModel() {
|
||||
private val sourceHandler: SourceInteractionHandler,
|
||||
contextWrapper: ContextWrapper
|
||||
) : ViewModel(contextWrapper) {
|
||||
|
||||
@Inject constructor(
|
||||
sourceHandler: SourceInteractionHandler,
|
||||
contextWrapper: ContextWrapper,
|
||||
params: Params
|
||||
) : this(
|
||||
params.source,
|
||||
sourceHandler
|
||||
sourceHandler,
|
||||
contextWrapper
|
||||
)
|
||||
|
||||
private val _mangas = MutableStateFlow(emptyList<Manga>())
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
package ca.gosyer.ui.sources.browse.components
|
||||
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import ca.gosyer.ui.base.components.VerticalScrollbar
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.forEachGesture
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -17,7 +17,7 @@ import androidx.compose.foundation.lazy.GridCells
|
||||
import androidx.compose.foundation.lazy.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import ca.gosyer.ui.base.components.rememberScrollbarAdapter
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Explore
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user