More stuff to the shared jvm module, android compatibility WIP

This commit is contained in:
Syer10
2022-02-26 20:35:04 -05:00
parent ceaa264a3a
commit a4ec64c67d
124 changed files with 733 additions and 319 deletions

View File

@@ -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 {

View File

@@ -12,4 +12,6 @@ object Config {
val desktopJvmTarget = JavaVersion.VERSION_16
val androidJvmTarget = JavaVersion.VERSION_11
const val androidDev = false
}

View File

@@ -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")
}
}
}

View File

@@ -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")
}
}
}

View File

@@ -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")
}
}
}

View File

@@ -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 }
}
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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) {
}

View File

@@ -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()
}

View File

@@ -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 }
}
}

View File

@@ -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
}

View File

@@ -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(

View File

@@ -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
}
}

View File

@@ -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) })
}
}
}
}

View File

@@ -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 {

View File

@@ -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)
}
}
}
}
}

View File

@@ -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)

View File

@@ -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()

View File

@@ -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()
}
}

View 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
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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(

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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()
}
}

View File

@@ -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()

View File

@@ -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()
}
*/

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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(

View File

@@ -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),

View File

@@ -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 = {}
)
}
}*/

View File

@@ -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

View File

@@ -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()
}

View File

@@ -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()

View File

@@ -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),

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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>())

View File

@@ -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