mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-10 06:42:05 +01:00
Start adding iOS support to presentation
This commit is contained in:
@@ -7,7 +7,9 @@
|
|||||||
package ca.gosyer.jui.core.io
|
package ca.gosyer.jui.core.io
|
||||||
|
|
||||||
import ca.gosyer.jui.core.lang.withIOContext
|
import ca.gosyer.jui.core.lang.withIOContext
|
||||||
|
import okio.Buffer
|
||||||
import okio.BufferedSink
|
import okio.BufferedSink
|
||||||
|
import okio.BufferedSource
|
||||||
import okio.FileSystem
|
import okio.FileSystem
|
||||||
import okio.Path
|
import okio.Path
|
||||||
import okio.Source
|
import okio.Source
|
||||||
@@ -32,3 +34,7 @@ suspend fun Source.copyTo(sink: BufferedSink) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ByteArray.source(): BufferedSource {
|
||||||
|
return Buffer().write(this)
|
||||||
|
}
|
||||||
@@ -25,6 +25,9 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
iosX64()
|
||||||
|
iosArm64()
|
||||||
|
iosSimulatorArm64()
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
all {
|
all {
|
||||||
@@ -53,13 +56,16 @@ kotlin {
|
|||||||
api(libs.dateTime)
|
api(libs.dateTime)
|
||||||
api(libs.immutableCollections)
|
api(libs.immutableCollections)
|
||||||
api(libs.aboutLibraries.core)
|
api(libs.aboutLibraries.core)
|
||||||
api(libs.aboutLibraries.ui)
|
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
api(projects.i18n)
|
api(projects.i18n)
|
||||||
api(projects.domain)
|
api(projects.domain)
|
||||||
api(projects.data)
|
api(projects.data)
|
||||||
api(projects.uiCore)
|
api(projects.uiCore)
|
||||||
api(compose.desktop.currentOs)
|
api(compose.runtime)
|
||||||
|
api(compose.foundation)
|
||||||
|
api(compose.ui)
|
||||||
|
api(compose.material)
|
||||||
api(compose("org.jetbrains.compose.ui:ui-util"))
|
api(compose("org.jetbrains.compose.ui:ui-util"))
|
||||||
api(compose.materialIconsExtended)
|
api(compose.materialIconsExtended)
|
||||||
}
|
}
|
||||||
@@ -75,6 +81,8 @@ kotlin {
|
|||||||
dependsOn(commonMain)
|
dependsOn(commonMain)
|
||||||
dependencies {
|
dependencies {
|
||||||
api(kotlin("stdlib-jdk8"))
|
api(kotlin("stdlib-jdk8"))
|
||||||
|
api(libs.aboutLibraries.ui)
|
||||||
|
api(compose.desktop.currentOs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jvmTest by creating {
|
val jvmTest by creating {
|
||||||
@@ -107,6 +115,22 @@ kotlin {
|
|||||||
val androidTest by getting {
|
val androidTest by getting {
|
||||||
dependsOn(jvmTest)
|
dependsOn(jvmTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val iosMain by creating {
|
||||||
|
dependsOn(commonMain)
|
||||||
|
}
|
||||||
|
val iosTest by creating {
|
||||||
|
dependsOn(commonTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
"iosX64",
|
||||||
|
"iosArm64",
|
||||||
|
"iosSimulatorArm64",
|
||||||
|
).forEach {
|
||||||
|
getByName(it + "Main").dependsOn(iosMain)
|
||||||
|
getByName(it + "Test").dependsOn(iosTest)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import com.mikepenz.aboutlibraries.Libs
|
|||||||
import com.mikepenz.aboutlibraries.entity.Library
|
import com.mikepenz.aboutlibraries.entity.Library
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.Libraries
|
import com.mikepenz.aboutlibraries.ui.compose.Libraries
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryColors
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryColors
|
||||||
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
||||||
import com.mikepenz.aboutlibraries.util.withContext
|
import com.mikepenz.aboutlibraries.util.withContext
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@@ -35,6 +36,10 @@ actual fun getLicenses(): Libs? {
|
|||||||
return libs
|
return libs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual typealias LibraryDefaults = LibraryDefaults
|
||||||
|
|
||||||
|
actual typealias LibraryColors = LibraryColors
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun InternalAboutLibraries(
|
actual fun InternalAboutLibraries(
|
||||||
libraries: ImmutableList<Library>,
|
libraries: ImmutableList<Library>,
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import androidx.compose.ui.Modifier
|
|||||||
actual fun Modifier.sourceSideMenuItem(
|
actual fun Modifier.sourceSideMenuItem(
|
||||||
onSourceTabClick: () -> Unit,
|
onSourceTabClick: () -> Unit,
|
||||||
onSourceCloseTabClick: () -> Unit
|
onSourceCloseTabClick: () -> Unit
|
||||||
): Modifier = Modifier.clickable(
|
): Modifier = clickable(
|
||||||
onClick = {
|
onClick = onSourceTabClick
|
||||||
onSourceTabClick()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,7 +7,10 @@
|
|||||||
package ca.gosyer.jui.ui.base.state
|
package ca.gosyer.jui.ui.base.state
|
||||||
|
|
||||||
import ca.gosyer.jui.uicore.vm.ViewModel
|
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||||
|
import kotlinx.coroutines.InternalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.internal.SynchronizedObject
|
||||||
|
import kotlinx.coroutines.internal.synchronized
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
@@ -17,14 +20,17 @@ fun <T> SavedStateHandle.getStateFlow(
|
|||||||
return SavedStateHandleDelegate(this, initialValue)
|
return SavedStateHandleDelegate(this, initialValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalCoroutinesApi::class)
|
||||||
class SavedStateHandleDelegate<T>(
|
class SavedStateHandleDelegate<T>(
|
||||||
private val savedStateHandle: SavedStateHandle,
|
private val savedStateHandle: SavedStateHandle,
|
||||||
private val initialValue: () -> T
|
private val initialValue: () -> T
|
||||||
) : ReadOnlyProperty<ViewModel, SavedStateHandleStateFlow<T>> {
|
) : ReadOnlyProperty<ViewModel, SavedStateHandleStateFlow<T>> {
|
||||||
|
private val synchronizedObject = SynchronizedObject()
|
||||||
|
|
||||||
private var item: SavedStateHandleStateFlow<T>? = null
|
private var item: SavedStateHandleStateFlow<T>? = null
|
||||||
|
|
||||||
override fun getValue(thisRef: ViewModel, property: KProperty<*>): SavedStateHandleStateFlow<T> {
|
override fun getValue(thisRef: ViewModel, property: KProperty<*>): SavedStateHandleStateFlow<T> {
|
||||||
return item ?: synchronized(this) {
|
return item ?: synchronized(synchronizedObject) {
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
savedStateHandle.getSavedStateFlow(property.name, initialValue)
|
savedStateHandle.getSavedStateFlow(property.name, initialValue)
|
||||||
.also { item = it }
|
.also { item = it }
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import ca.gosyer.jui.ui.viewModel
|
|||||||
import cafe.adriel.voyager.core.screen.Screen
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
import cafe.adriel.voyager.core.screen.ScreenKey
|
import cafe.adriel.voyager.core.screen.ScreenKey
|
||||||
import cafe.adriel.voyager.core.screen.uniqueScreenKey
|
import cafe.adriel.voyager.core.screen.uniqueScreenKey
|
||||||
|
import kotlin.jvm.Transient
|
||||||
|
|
||||||
expect class CategoriesLauncher {
|
expect class CategoriesLauncher {
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import ca.gosyer.jui.domain.updates.interactor.UpdateLibrary
|
|||||||
import ca.gosyer.jui.i18n.MR
|
import ca.gosyer.jui.i18n.MR
|
||||||
import ca.gosyer.jui.ui.base.state.SavedStateHandle
|
import ca.gosyer.jui.ui.base.state.SavedStateHandle
|
||||||
import ca.gosyer.jui.ui.base.state.getStateFlow
|
import ca.gosyer.jui.ui.base.state.getStateFlow
|
||||||
import ca.gosyer.jui.ui.util.lang.Collator
|
import ca.gosyer.jui.ui.util.lang.CollatorComparator
|
||||||
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
import ca.gosyer.jui.uicore.vm.ViewModel
|
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
@@ -191,7 +191,7 @@ class LibraryScreenViewModel @Inject constructor(
|
|||||||
val sortFn: (Manga, Manga) -> Int = when (sortMode) {
|
val sortFn: (Manga, Manga) -> Int = when (sortMode) {
|
||||||
Sort.ALPHABETICAL -> {
|
Sort.ALPHABETICAL -> {
|
||||||
val locale = Locale.current
|
val locale = Locale.current
|
||||||
val collator = Collator(locale);
|
val collator = CollatorComparator(locale);
|
||||||
|
|
||||||
{ a, b ->
|
{ a, b ->
|
||||||
collator.compare(a.title.toLowerCase(locale), b.title.toLowerCase(locale))
|
collator.compare(a.title.toLowerCase(locale), b.title.toLowerCase(locale))
|
||||||
|
|||||||
@@ -19,11 +19,14 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Scaffold
|
import androidx.compose.material.Scaffold
|
||||||
|
import androidx.compose.material.contentColorFor
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ca.gosyer.jui.i18n.MR
|
import ca.gosyer.jui.i18n.MR
|
||||||
@@ -38,8 +41,6 @@ import ca.gosyer.jui.uicore.insets.statusBars
|
|||||||
import ca.gosyer.jui.uicore.resources.stringResource
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
import com.mikepenz.aboutlibraries.Libs
|
import com.mikepenz.aboutlibraries.Libs
|
||||||
import com.mikepenz.aboutlibraries.entity.Library
|
import com.mikepenz.aboutlibraries.entity.Library
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryColors
|
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
@@ -60,6 +61,18 @@ internal expect fun InternalAboutLibraries(
|
|||||||
onLibraryClick: ((Library) -> Unit)?
|
onLibraryClick: ((Library) -> Unit)?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
expect interface LibraryColors
|
||||||
|
expect object LibraryDefaults {
|
||||||
|
@Composable
|
||||||
|
fun libraryColors(
|
||||||
|
backgroundColor: Color = MaterialTheme.colors.background,
|
||||||
|
contentColor: Color = contentColorFor(backgroundColor),
|
||||||
|
badgeBackgroundColor: Color = MaterialTheme.colors.primary,
|
||||||
|
badgeContentColor: Color = contentColorFor(badgeBackgroundColor),
|
||||||
|
): LibraryColors
|
||||||
|
val ContentPadding: PaddingValues
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutLibraries(
|
fun AboutLibraries(
|
||||||
libraries: ImmutableList<Library>,
|
libraries: ImmutableList<Library>,
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.ui.reader.loader
|
package ca.gosyer.jui.ui.reader.loader
|
||||||
|
|
||||||
|
import ca.gosyer.jui.core.io.SYSTEM
|
||||||
|
import ca.gosyer.jui.core.lang.IO
|
||||||
import ca.gosyer.jui.core.lang.PriorityChannel
|
import ca.gosyer.jui.core.lang.PriorityChannel
|
||||||
import ca.gosyer.jui.core.lang.throwIfCancellation
|
import ca.gosyer.jui.core.lang.throwIfCancellation
|
||||||
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPage
|
import ca.gosyer.jui.domain.chapter.interactor.GetChapterPage
|
||||||
@@ -39,6 +41,7 @@ import kotlinx.coroutines.launch
|
|||||||
import okio.BufferedSource
|
import okio.BufferedSource
|
||||||
import okio.FileSystem
|
import okio.FileSystem
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
|
import okio.use
|
||||||
import org.lighthousegames.logging.logging
|
import org.lighthousegames.logging.logging
|
||||||
|
|
||||||
class TachideskPageLoader(
|
class TachideskPageLoader(
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ca.gosyer.jui.core.io.SYSTEM
|
||||||
import ca.gosyer.jui.core.io.copyTo
|
import ca.gosyer.jui.core.io.copyTo
|
||||||
import ca.gosyer.jui.core.io.saveTo
|
import ca.gosyer.jui.core.io.saveTo
|
||||||
|
import ca.gosyer.jui.core.lang.IO
|
||||||
import ca.gosyer.jui.core.lang.throwIfCancellation
|
import ca.gosyer.jui.core.lang.throwIfCancellation
|
||||||
import ca.gosyer.jui.domain.backup.interactor.ExportBackupFile
|
import ca.gosyer.jui.domain.backup.interactor.ExportBackupFile
|
||||||
import ca.gosyer.jui.domain.backup.interactor.ImportBackupFile
|
import ca.gosyer.jui.domain.backup.interactor.ImportBackupFile
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
package ca.gosyer.jui.ui.sources.globalsearch
|
package ca.gosyer.jui.ui.sources.globalsearch
|
||||||
|
|
||||||
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
import androidx.compose.runtime.snapshots.SnapshotStateMap
|
||||||
|
import ca.gosyer.jui.core.lang.IO
|
||||||
import ca.gosyer.jui.domain.manga.model.Manga
|
import ca.gosyer.jui.domain.manga.model.Manga
|
||||||
import ca.gosyer.jui.domain.source.interactor.GetSearchManga
|
import ca.gosyer.jui.domain.source.interactor.GetSearchManga
|
||||||
import ca.gosyer.jui.domain.source.interactor.GetSourceList
|
import ca.gosyer.jui.domain.source.interactor.GetSourceList
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ package ca.gosyer.jui.ui.util.lang
|
|||||||
|
|
||||||
import androidx.compose.ui.text.intl.Locale
|
import androidx.compose.ui.text.intl.Locale
|
||||||
|
|
||||||
expect fun Collator(locale: Locale): Collator
|
expect class CollatorComparator(locale: Locale) : Comparator<String> {
|
||||||
|
override fun compare(source: String, target: String): Int
|
||||||
expect class Collator {
|
|
||||||
fun compare(source: String, target: String): Int
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ package ca.gosyer.jui.ui.util.lang
|
|||||||
import io.ktor.utils.io.ByteReadChannel
|
import io.ktor.utils.io.ByteReadChannel
|
||||||
import okio.Source
|
import okio.Source
|
||||||
|
|
||||||
expect fun ByteReadChannel.toSource(): Source
|
expect suspend fun ByteReadChannel.toSource(): Source
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import com.mikepenz.aboutlibraries.Libs
|
|||||||
import com.mikepenz.aboutlibraries.entity.Library
|
import com.mikepenz.aboutlibraries.entity.Library
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.Libraries
|
import com.mikepenz.aboutlibraries.ui.compose.Libraries
|
||||||
import com.mikepenz.aboutlibraries.ui.compose.LibraryColors
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryColors
|
||||||
|
import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -33,6 +34,10 @@ actual fun getLicenses(): Libs? {
|
|||||||
return libs
|
return libs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual typealias LibraryDefaults = LibraryDefaults
|
||||||
|
|
||||||
|
actual typealias LibraryColors = LibraryColors
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun InternalAboutLibraries(
|
actual fun InternalAboutLibraries(
|
||||||
libraries: ImmutableList<Library>,
|
libraries: ImmutableList<Library>,
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisallowComposableCalls
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import ca.gosyer.jui.ui.base.LocalViewModels
|
||||||
|
import ca.gosyer.jui.ui.base.state.SavedStateHandle
|
||||||
|
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||||
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
|
||||||
|
actual interface ViewModelComponent : SharedViewModelComponent
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual inline fun <reified VM : ViewModel> Screen.stateViewModel(
|
||||||
|
tag: String?,
|
||||||
|
crossinline factory: @DisallowComposableCalls ViewModelComponent.(SavedStateHandle) -> VM
|
||||||
|
): VM {
|
||||||
|
val viewModelFactory = LocalViewModels.current
|
||||||
|
val savedStateHandle = rememberSaveable { SavedStateHandle() }
|
||||||
|
return rememberScreenModel(tag) { viewModelFactory.factory(savedStateHandle) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.DpOffset
|
||||||
|
|
||||||
|
actual interface TooltipPlacement
|
||||||
|
|
||||||
|
actual class CursorPoint actual constructor(
|
||||||
|
offset: DpOffset,
|
||||||
|
alignment: Alignment,
|
||||||
|
windowMargin: Dp
|
||||||
|
) : TooltipPlacement
|
||||||
|
|
||||||
|
actual class ComponentRect actual constructor(
|
||||||
|
anchor: Alignment,
|
||||||
|
alignment: Alignment,
|
||||||
|
offset: DpOffset
|
||||||
|
) : TooltipPlacement
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun TooltipArea(
|
||||||
|
tooltip: @Composable () -> Unit,
|
||||||
|
modifier: Modifier,
|
||||||
|
delayMillis: Int,
|
||||||
|
tooltipPlacement: TooltipPlacement,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Box(Modifier) {
|
||||||
|
content()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.file
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import okio.Source
|
||||||
|
|
||||||
|
actual class FileChooser(private val onFileFound: (Source) -> Unit) {
|
||||||
|
actual fun launch(extension: String) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun rememberFileChooser(onFileFound: (Source) -> Unit): FileChooser {
|
||||||
|
return remember { FileChooser(onFileFound) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.file
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import okio.Sink
|
||||||
|
|
||||||
|
actual class FileSaver(
|
||||||
|
private val onFileSelected: (Sink) -> Unit,
|
||||||
|
private val onCancel: () -> Unit,
|
||||||
|
private val onError: () -> Unit,
|
||||||
|
) {
|
||||||
|
actual fun save(name: String) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun rememberFileSaver(
|
||||||
|
onFileSelected: (Sink) -> Unit,
|
||||||
|
onCancel: () -> Unit,
|
||||||
|
onError: () -> Unit
|
||||||
|
): FileSaver {
|
||||||
|
return remember { FileSaver(onFileSelected, onCancel, onError) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.image
|
||||||
|
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import com.seiko.imageloader.component.decoder.Decoder
|
||||||
|
import com.seiko.imageloader.component.decoder.SkiaImageDecoder
|
||||||
|
|
||||||
|
actual class BitmapDecoderFactory actual constructor(contextWrapper: ContextWrapper) :
|
||||||
|
Decoder.Factory by SkiaImageDecoder.Factory()
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.image
|
||||||
|
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import com.seiko.imageloader.ImageLoaderBuilder
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCache
|
||||||
|
import com.seiko.imageloader.cache.disk.DiskCacheBuilder
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCache
|
||||||
|
import com.seiko.imageloader.cache.memory.MemoryCacheBuilder
|
||||||
|
import com.seiko.imageloader.request.Options
|
||||||
|
import okio.Path.Companion.toPath
|
||||||
|
import platform.Foundation.NSCachesDirectory
|
||||||
|
import platform.Foundation.NSFileManager
|
||||||
|
import platform.Foundation.NSUserDomainMask
|
||||||
|
|
||||||
|
actual val imageConfig: Options.ImageConfig = Options.ImageConfig.ARGB_8888
|
||||||
|
|
||||||
|
actual fun imageLoaderBuilder(contextWrapper: ContextWrapper): ImageLoaderBuilder {
|
||||||
|
return ImageLoaderBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun diskCache(contextWrapper: ContextWrapper, cacheDir: String): DiskCache {
|
||||||
|
return DiskCacheBuilder()
|
||||||
|
.directory(getCacheDir().toPath() / cacheDir)
|
||||||
|
.maxSizeBytes(1024 * 1024 * 150) // 150 MB
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCacheDir(): String {
|
||||||
|
return NSFileManager.defaultManager.URLForDirectory(
|
||||||
|
NSCachesDirectory, NSUserDomainMask, null, true, null
|
||||||
|
)!!.path.orEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun memoryCache(contextWrapper: ContextWrapper): MemoryCache {
|
||||||
|
return MemoryCacheBuilder()
|
||||||
|
.maxSizePercent(0.25)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.navigation
|
||||||
|
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.IconButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
|
||||||
|
// todo
|
||||||
|
@Composable
|
||||||
|
actual fun ActionIcon(onClick: () -> Unit, contentDescription: String, icon: ImageVector) {
|
||||||
|
IconButton(onClick = onClick) {
|
||||||
|
Icon(icon, contentDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.navigation
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun BackHandler(enabled: Boolean, onBack: () -> Unit) {}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.prefs
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import kotlinx.cinterop.alloc
|
||||||
|
import kotlinx.cinterop.memScoped
|
||||||
|
import kotlinx.cinterop.ptr
|
||||||
|
import kotlinx.cinterop.value
|
||||||
|
import platform.CoreGraphics.CGFloatVar
|
||||||
|
import platform.UIKit.UIColor
|
||||||
|
|
||||||
|
fun Color.toUIColor() = UIColor(red.toDouble(), green.toDouble(), blue.toDouble(), 1.0)
|
||||||
|
|
||||||
|
internal actual fun Color.toHsv(): FloatArray = memScoped {
|
||||||
|
val uiColor = toUIColor()
|
||||||
|
val hue = alloc<CGFloatVar>()
|
||||||
|
val saturation = alloc<CGFloatVar>()
|
||||||
|
val brightness = alloc<CGFloatVar>()
|
||||||
|
val alpha = alloc<CGFloatVar>()
|
||||||
|
uiColor.getHue(hue.ptr, saturation.ptr, brightness.ptr, alpha.ptr)
|
||||||
|
|
||||||
|
floatArrayOf(hue.value.toFloat(), saturation.value.toFloat(), brightness.value.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
internal actual fun hexStringToColor(hex: String): Color? {
|
||||||
|
return try {
|
||||||
|
val i = hex.removePrefix("#").toInt(16)
|
||||||
|
Color(i shr 16 and 0xFF, i shr 8 and 0xFF, i and 0xFF)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.screen
|
||||||
|
|
||||||
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
import cafe.adriel.voyager.core.screen.ScreenKey
|
||||||
|
import cafe.adriel.voyager.core.screen.uniqueScreenKey
|
||||||
|
|
||||||
|
actual abstract class BaseScreen : Screen {
|
||||||
|
|
||||||
|
override val key: ScreenKey = uniqueScreenKey
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.state
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
|
||||||
|
actual class SavedStateHandle {
|
||||||
|
private val regular = mutableMapOf<String, Any?>()
|
||||||
|
private val flows = mutableMapOf<String, MutableStateFlow<Any?>>()
|
||||||
|
|
||||||
|
actual operator fun <T> get(key: String): T? {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return regular[key] as T?
|
||||||
|
}
|
||||||
|
|
||||||
|
actual operator fun <T> set(key: String, value: T?) {
|
||||||
|
regular[key] = value
|
||||||
|
flows[key]?.value = value
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun <T> remove(key: String): T? {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val latestValue = regular.remove(key) as T?
|
||||||
|
flows.remove(key)
|
||||||
|
return latestValue
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun <T> getStateFlow(
|
||||||
|
key: String,
|
||||||
|
initialValue: T
|
||||||
|
): StateFlow<T> {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
// If a flow exists we should just return it, and since it is a StateFlow and a value must
|
||||||
|
// always be set, we know a value must already be available
|
||||||
|
return flows.getOrPut(key) {
|
||||||
|
// If there is not a value associated with the key, add the initial value, otherwise,
|
||||||
|
// use the one we already have.
|
||||||
|
if (!regular.containsKey(key)) {
|
||||||
|
regular[key] = initialValue
|
||||||
|
}
|
||||||
|
MutableStateFlow(regular[key]).apply { flows[key] = this }
|
||||||
|
}.asStateFlow() as StateFlow<T>
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.base.theme
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import ca.gosyer.jui.uicore.components.ScrollbarStyle
|
||||||
|
|
||||||
|
actual object ThemeScrollbarStyle {
|
||||||
|
private val defaultScrollbarStyle = ScrollbarStyle()
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
@Composable
|
||||||
|
actual fun getScrollbarStyle(): ScrollbarStyle {
|
||||||
|
return defaultScrollbarStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.categories
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
|
|
||||||
|
actual class CategoriesLauncher(private val navigator: Navigator?) {
|
||||||
|
|
||||||
|
actual fun open() {
|
||||||
|
navigator?.push(CategoriesScreen())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun CategoriesWindow() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun rememberCategoriesLauncher(notifyFinished: () -> Unit): CategoriesLauncher {
|
||||||
|
val navigator = LocalNavigator.current
|
||||||
|
return remember(navigator) { CategoriesLauncher(navigator) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.downloads
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.base.WebsocketService
|
||||||
|
import ca.gosyer.jui.domain.download.service.DownloadService
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
|
||||||
|
internal actual fun startDownloadService(
|
||||||
|
contextWrapper: ContextWrapper,
|
||||||
|
downloadService: DownloadService,
|
||||||
|
actions: WebsocketService.Actions
|
||||||
|
) {
|
||||||
|
downloadService.init()
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.library.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
|
import androidx.compose.material.DropdownMenu
|
||||||
|
import androidx.compose.material.DropdownMenuItem
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.composed
|
||||||
|
import ca.gosyer.jui.i18n.MR
|
||||||
|
import ca.gosyer.jui.uicore.resources.stringResource
|
||||||
|
|
||||||
|
actual fun Modifier.libraryMangaModifier(
|
||||||
|
onClickManga: () -> Unit,
|
||||||
|
onClickRemoveManga: () -> Unit
|
||||||
|
): Modifier = composed {
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
DropdownMenu(
|
||||||
|
expanded,
|
||||||
|
onDismissRequest = { expanded = false }
|
||||||
|
) {
|
||||||
|
listOf(
|
||||||
|
stringResource(MR.strings.action_remove_favorite) to onClickRemoveManga
|
||||||
|
).forEach { (label, onClick) ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
expanded = false
|
||||||
|
onClick()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(text = label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Modifier.combinedClickable(
|
||||||
|
onClick = { onClickManga() },
|
||||||
|
onLongClick = {
|
||||||
|
expanded = true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.main.about.components
|
||||||
|
|
||||||
|
import ca.gosyer.jui.presentation.build.BuildKonfig
|
||||||
|
import platform.UIKit.UIDevice
|
||||||
|
|
||||||
|
actual fun getDebugInfo(): String {
|
||||||
|
val device = UIDevice.currentDevice
|
||||||
|
return """
|
||||||
|
App version: ${BuildKonfig.VERSION} (${ if (BuildKonfig.DEBUG) "Debug" else "Standard"}, ${BuildKonfig.MIGRATION_CODE})
|
||||||
|
Preview build: r${BuildKonfig.PREVIEW_BUILD}
|
||||||
|
Device name: ${device.name}
|
||||||
|
Device model: ${device.model}
|
||||||
|
System name: ${device.systemName}
|
||||||
|
System version: ${device.systemVersion}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.main.about.licenses.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import ca.gosyer.jui.core.lang.withIOContext
|
||||||
|
import ca.gosyer.jui.i18n.MR
|
||||||
|
import com.mikepenz.aboutlibraries.Libs
|
||||||
|
import com.mikepenz.aboutlibraries.entity.Library
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun getLicenses(): Libs? {
|
||||||
|
val libs by produceState<Libs?>(
|
||||||
|
null
|
||||||
|
) {
|
||||||
|
withIOContext {
|
||||||
|
val json = MR.files.aboutlibraries.readText()
|
||||||
|
value = Libs.Builder().withJson(json).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return libs
|
||||||
|
}
|
||||||
|
|
||||||
|
actual object LibraryDefaults {
|
||||||
|
@Composable
|
||||||
|
actual fun libraryColors(
|
||||||
|
backgroundColor: Color,
|
||||||
|
contentColor: Color,
|
||||||
|
badgeBackgroundColor: Color,
|
||||||
|
badgeContentColor: Color,
|
||||||
|
): LibraryColors = object : LibraryColors {}
|
||||||
|
|
||||||
|
actual val ContentPadding: PaddingValues get() = PaddingValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual interface LibraryColors
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun InternalAboutLibraries(
|
||||||
|
libraries: ImmutableList<Library>,
|
||||||
|
modifier: Modifier,
|
||||||
|
lazyListState: LazyListState,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
|
showAuthor: Boolean,
|
||||||
|
showVersion: Boolean,
|
||||||
|
showLicenseBadges: Boolean,
|
||||||
|
colors: LibraryColors,
|
||||||
|
itemContentPadding: PaddingValues,
|
||||||
|
onLibraryClick: ((Library) -> Unit)?
|
||||||
|
) {
|
||||||
|
/*Libraries(
|
||||||
|
libraries = libraries,
|
||||||
|
modifier = modifier,
|
||||||
|
lazyListState = lazyListState,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
showAuthor = showAuthor,
|
||||||
|
showVersion = showVersion,
|
||||||
|
showLicenseBadges = showLicenseBadges,
|
||||||
|
colors = colors,
|
||||||
|
itemContentPadding = itemContentPadding,
|
||||||
|
onLibraryClick = onLibraryClick
|
||||||
|
)*/
|
||||||
|
}
|
||||||
@@ -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.jui.ui.main.components
|
||||||
|
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
|
actual class DebugOverlayViewModel @Inject constructor(contextWrapper: ContextWrapper) : ViewModel(contextWrapper) {
|
||||||
|
actual val maxMemory: String
|
||||||
|
get() = ""
|
||||||
|
actual val usedMemoryFlow: MutableStateFlow<String> = MutableStateFlow("")
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.main.components
|
||||||
|
|
||||||
|
import ca.gosyer.jui.domain.base.WebsocketService
|
||||||
|
import ca.gosyer.jui.domain.library.service.LibraryUpdateService
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
|
||||||
|
internal actual fun startLibraryUpdatesService(
|
||||||
|
contextWrapper: ContextWrapper,
|
||||||
|
libraryUpdatesService: LibraryUpdateService,
|
||||||
|
actions: WebsocketService.Actions
|
||||||
|
) {
|
||||||
|
libraryUpdatesService.init()
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.manga.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
actual fun Modifier.chapterItemModifier(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
markRead: (() -> Unit)?,
|
||||||
|
markUnread: (() -> Unit)?,
|
||||||
|
bookmarkChapter: (() -> Unit)?,
|
||||||
|
unBookmarkChapter: (() -> Unit)?,
|
||||||
|
markPreviousAsRead: () -> Unit,
|
||||||
|
onSelectChapter: (() -> Unit)?,
|
||||||
|
onUnselectChapter: (() -> Unit)?
|
||||||
|
): Modifier = combinedClickable(
|
||||||
|
onClick = onUnselectChapter ?: onClick,
|
||||||
|
onLongClick = onSelectChapter
|
||||||
|
)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.reader
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import ca.gosyer.jui.ui.base.model.StableHolder
|
||||||
|
import cafe.adriel.voyager.core.screen.Screen
|
||||||
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
|
||||||
|
class ReaderScreen(val chapterIndex: Int, val mangaId: Long) : Screen {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun Content() {
|
||||||
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
ReaderMenu(
|
||||||
|
chapterIndex,
|
||||||
|
mangaId,
|
||||||
|
remember { StableHolder(MutableSharedFlow()) },
|
||||||
|
navigator::pop
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual class ReaderLauncher(private val navigator: Navigator?) {
|
||||||
|
|
||||||
|
actual fun launch(
|
||||||
|
chapterIndex: Int,
|
||||||
|
mangaId: Long
|
||||||
|
) {
|
||||||
|
navigator?.push(ReaderScreen(chapterIndex, mangaId))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun Reader() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun rememberReaderLauncher(): ReaderLauncher {
|
||||||
|
val navigator = LocalNavigator.current
|
||||||
|
return remember(navigator) { ReaderLauncher(navigator) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.settings
|
||||||
|
|
||||||
|
actual val showWindowDecorationsOption: Boolean = false
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import ca.gosyer.jui.uicore.vm.ContextWrapper
|
||||||
|
import ca.gosyer.jui.uicore.vm.ViewModel
|
||||||
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun getServerHostItems(viewModel: @Composable () -> SettingsServerHostViewModel): LazyListScope.() -> Unit {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual class SettingsServerHostViewModel @Inject constructor(contextWrapper: ContextWrapper) : ViewModel(contextWrapper)
|
||||||
@@ -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.jui.ui.sources.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
actual fun Modifier.sourceSideMenuItem(
|
||||||
|
onSourceTabClick: () -> Unit,
|
||||||
|
onSourceCloseTabClick: () -> Unit
|
||||||
|
): Modifier = clickable(
|
||||||
|
onClick = onSourceTabClick
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.updates.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.combinedClickable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
actual fun Modifier.updatesItemModifier(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
markRead: (() -> Unit)?,
|
||||||
|
markUnread: (() -> Unit)?,
|
||||||
|
bookmarkChapter: (() -> Unit)?,
|
||||||
|
unBookmarkChapter: (() -> Unit)?,
|
||||||
|
onSelectChapter: (() -> Unit)?,
|
||||||
|
onUnselectChapter: (() -> Unit)?
|
||||||
|
): Modifier = combinedClickable(
|
||||||
|
onClick = onUnselectChapter ?: onClick,
|
||||||
|
onLongClick = onSelectChapter
|
||||||
|
)
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.util.compose
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.asComposeImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||||
|
import io.ktor.client.call.body
|
||||||
|
import io.ktor.client.statement.HttpResponse
|
||||||
|
import org.jetbrains.skia.Image
|
||||||
|
import com.seiko.imageloader.Image as ImageLoaderImage
|
||||||
|
|
||||||
|
actual suspend fun HttpResponse.toImageBitmap(): ImageBitmap {
|
||||||
|
return Image.makeFromEncoded(body<ByteArray>()).toComposeImageBitmap()
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun ImageLoaderImage.asImageBitmap(): ImageBitmap {
|
||||||
|
return asComposeImageBitmap()
|
||||||
|
}
|
||||||
@@ -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.jui.ui.util.compose
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import platform.Foundation.NSString
|
||||||
|
import platform.Foundation.stringWithFormat
|
||||||
|
|
||||||
|
actual fun Color.toHexString(): String {
|
||||||
|
return NSString.stringWithFormat("#%06X", (0xFFFFFF and toArgb()))
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun Color.toLong() = NSString.stringWithFormat("%06X", 0xFFFFFF and toArgb()).toLong(16)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.util.lang
|
||||||
|
|
||||||
|
import androidx.compose.ui.text.intl.Locale
|
||||||
|
import platform.Foundation.NSString
|
||||||
|
import platform.Foundation.localizedCaseInsensitiveCompare
|
||||||
|
|
||||||
|
actual class CollatorComparator() : Comparator<String> {
|
||||||
|
|
||||||
|
actual constructor(locale: Locale) : this()
|
||||||
|
|
||||||
|
actual override fun compare(source: String, target: String): Int {
|
||||||
|
@Suppress("CAST_NEVER_SUCCEEDS")
|
||||||
|
return (source as NSString).localizedCaseInsensitiveCompare(target).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.util.lang
|
||||||
|
|
||||||
|
import ca.gosyer.jui.core.io.source
|
||||||
|
import io.ktor.util.toByteArray
|
||||||
|
import io.ktor.utils.io.ByteReadChannel
|
||||||
|
import okio.Source
|
||||||
|
|
||||||
|
actual suspend fun ByteReadChannel.toSource(): Source {
|
||||||
|
return this.toByteArray().source()
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* 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.jui.ui.util.lang
|
||||||
|
|
||||||
|
import platform.Foundation.NSString
|
||||||
|
import platform.Foundation.stringWithFormat
|
||||||
|
|
||||||
|
// Taken from https://github.com/icerockdev/moko-resources/blob/master/resources/src/appleMain/kotlin/dev/icerock/moko/resources/desc/Utils.kt
|
||||||
|
actual fun stringFormat(string: String, vararg args: Any?): String {
|
||||||
|
// NSString format works with NSObjects via %@, we should change standard format to %@
|
||||||
|
val objcFormat = string.replace(Regex("%((?:\\.|\\d|\\$)*)[abcdefs]"), "%$1@")
|
||||||
|
// bad but objc interop limited :(
|
||||||
|
// When calling variadic C functions spread operator is supported only for *arrayOf(...)
|
||||||
|
@Suppress("MagicNumber")
|
||||||
|
return when (args.size) {
|
||||||
|
0 -> NSString.stringWithFormat(objcFormat)
|
||||||
|
1 -> NSString.stringWithFormat(objcFormat, args[0])
|
||||||
|
2 -> NSString.stringWithFormat(objcFormat, args[0], args[1])
|
||||||
|
3 -> NSString.stringWithFormat(objcFormat, args[0], args[1], args[2])
|
||||||
|
4 -> NSString.stringWithFormat(objcFormat, args[0], args[1], args[2], args[3])
|
||||||
|
5 -> NSString.stringWithFormat(objcFormat, args[0], args[1], args[2], args[3], args[4])
|
||||||
|
6 -> NSString.stringWithFormat(
|
||||||
|
objcFormat,
|
||||||
|
args[0],
|
||||||
|
args[1],
|
||||||
|
args[2],
|
||||||
|
args[3],
|
||||||
|
args[4],
|
||||||
|
args[5]
|
||||||
|
)
|
||||||
|
7 -> NSString.stringWithFormat(
|
||||||
|
objcFormat,
|
||||||
|
args[0],
|
||||||
|
args[1],
|
||||||
|
args[2],
|
||||||
|
args[3],
|
||||||
|
args[4],
|
||||||
|
args[5],
|
||||||
|
args[6]
|
||||||
|
)
|
||||||
|
8 -> NSString.stringWithFormat(
|
||||||
|
objcFormat,
|
||||||
|
args[0],
|
||||||
|
args[1],
|
||||||
|
args[2],
|
||||||
|
args[3],
|
||||||
|
args[4],
|
||||||
|
args[5],
|
||||||
|
args[6],
|
||||||
|
args[7]
|
||||||
|
)
|
||||||
|
9 -> NSString.stringWithFormat(
|
||||||
|
objcFormat,
|
||||||
|
args[0],
|
||||||
|
args[1],
|
||||||
|
args[2],
|
||||||
|
args[3],
|
||||||
|
args[4],
|
||||||
|
args[5],
|
||||||
|
args[6],
|
||||||
|
args[7],
|
||||||
|
args[8]
|
||||||
|
)
|
||||||
|
else -> throw IllegalArgumentException("can't handle more then 9 arguments now")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,17 +8,17 @@ package ca.gosyer.jui.ui.util.lang
|
|||||||
|
|
||||||
import androidx.compose.ui.text.intl.Locale
|
import androidx.compose.ui.text.intl.Locale
|
||||||
import ca.gosyer.jui.core.lang.toPlatform
|
import ca.gosyer.jui.core.lang.toPlatform
|
||||||
import java.text.Collator as JvmCollator
|
import java.text.Collator
|
||||||
|
|
||||||
actual fun Collator(locale: Locale): Collator {
|
actual class CollatorComparator(private val collator: Collator) : Comparator<String> {
|
||||||
return Collator(JvmCollator.getInstance(locale.toPlatform()))
|
|
||||||
}
|
actual constructor(locale: Locale) : this(Collator.getInstance(locale.toPlatform()))
|
||||||
|
|
||||||
actual class Collator(private val jvmCollator: JvmCollator) {
|
|
||||||
init {
|
init {
|
||||||
jvmCollator.strength = JvmCollator.PRIMARY
|
collator.strength = Collator.PRIMARY
|
||||||
}
|
}
|
||||||
actual fun compare(source: String, target: String): Int {
|
|
||||||
return jvmCollator.compare(source, target)
|
actual override fun compare(source: String, target: String): Int {
|
||||||
|
return collator.compare(source, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,6 @@ import io.ktor.utils.io.jvm.javaio.toInputStream
|
|||||||
import okio.Source
|
import okio.Source
|
||||||
import okio.source
|
import okio.source
|
||||||
|
|
||||||
actual fun ByteReadChannel.toSource(): Source {
|
actual suspend fun ByteReadChannel.toSource(): Source {
|
||||||
return toInputStream().source()
|
return toInputStream().source()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,8 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.uicore.resources
|
package ca.gosyer.jui.uicore.resources
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import dev.icerock.moko.resources.desc.PluralFormattedStringDesc
|
||||||
import dev.icerock.moko.resources.PluralsResource
|
import dev.icerock.moko.resources.desc.PluralStringDesc
|
||||||
import dev.icerock.moko.resources.desc.Plural
|
|
||||||
import dev.icerock.moko.resources.desc.PluralFormatted
|
|
||||||
import dev.icerock.moko.resources.desc.StringDesc
|
|
||||||
|
|
||||||
@Composable
|
actual fun PluralStringDesc.localized(): String = localized()
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int): String =
|
actual fun PluralFormattedStringDesc.localized() = localized()
|
||||||
StringDesc.Plural(resource, quantity).localized()
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int, vararg args: Any): String =
|
|
||||||
StringDesc.PluralFormatted(resource, quantity, *args).localized()
|
|
||||||
@@ -7,11 +7,19 @@
|
|||||||
package ca.gosyer.jui.uicore.resources
|
package ca.gosyer.jui.uicore.resources
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import dev.icerock.moko.resources.PluralsResource
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
|
import dev.icerock.moko.resources.desc.Plural
|
||||||
|
import dev.icerock.moko.resources.desc.PluralFormatted
|
||||||
|
import dev.icerock.moko.resources.desc.PluralFormattedStringDesc
|
||||||
|
import dev.icerock.moko.resources.desc.PluralStringDesc
|
||||||
import dev.icerock.moko.resources.desc.Resource
|
import dev.icerock.moko.resources.desc.Resource
|
||||||
import dev.icerock.moko.resources.desc.ResourceFormatted
|
import dev.icerock.moko.resources.desc.ResourceFormatted
|
||||||
import dev.icerock.moko.resources.desc.StringDesc
|
import dev.icerock.moko.resources.desc.StringDesc
|
||||||
|
|
||||||
|
expect fun PluralStringDesc.localized(): String
|
||||||
|
expect fun PluralFormattedStringDesc.localized(): String
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun stringResource(resource: StringResource): String =
|
actual fun stringResource(resource: StringResource): String =
|
||||||
StringDesc.Resource(resource).localized()
|
StringDesc.Resource(resource).localized()
|
||||||
@@ -20,7 +28,6 @@ actual fun stringResource(resource: StringResource): String =
|
|||||||
actual fun stringResource(resource: StringResource, vararg args: Any): String =
|
actual fun stringResource(resource: StringResource, vararg args: Any): String =
|
||||||
StringDesc.ResourceFormatted(resource, *args).localized()
|
StringDesc.ResourceFormatted(resource, *args).localized()
|
||||||
|
|
||||||
/* TODO the commonizer chokes on .localized()
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int): String =
|
actual fun stringResource(resource: PluralsResource, quantity: Int): String =
|
||||||
StringDesc.Plural(resource, quantity).localized()
|
StringDesc.Plural(resource, quantity).localized()
|
||||||
@@ -28,4 +35,3 @@ actual fun stringResource(resource: PluralsResource, quantity: Int): String =
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int, vararg args: Any): String =
|
actual fun stringResource(resource: PluralsResource, quantity: Int, vararg args: Any): String =
|
||||||
StringDesc.PluralFormatted(resource, quantity, *args).localized()
|
StringDesc.PluralFormatted(resource, quantity, *args).localized()
|
||||||
*/
|
|
||||||
|
|||||||
@@ -6,17 +6,28 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.uicore.vm
|
package ca.gosyer.jui.uicore.vm
|
||||||
|
|
||||||
|
import ca.gosyer.jui.core.lang.launchDefault
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
|
import dev.icerock.moko.resources.desc.desc
|
||||||
import dev.icerock.moko.resources.format
|
import dev.icerock.moko.resources.format
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.asSharedFlow
|
||||||
import me.tatarka.inject.annotations.Inject
|
import me.tatarka.inject.annotations.Inject
|
||||||
|
|
||||||
actual class ContextWrapper @Inject constructor() {
|
actual class ContextWrapper @Inject constructor() {
|
||||||
|
private val _toasts = MutableSharedFlow<Pair<String, Length>>()
|
||||||
|
val toasts = _toasts.asSharedFlow()
|
||||||
|
|
||||||
actual fun toPlatformString(stringResource: StringResource): String {
|
actual fun toPlatformString(stringResource: StringResource): String {
|
||||||
return stringResource.localized()
|
return stringResource.desc().localized()
|
||||||
}
|
}
|
||||||
actual fun toPlatformString(stringResource: StringResource, vararg args: Any): String {
|
actual fun toPlatformString(stringResource: StringResource, vararg args: Any): String {
|
||||||
return stringResource.format(*args).localized()
|
return stringResource.format(*args).localized()
|
||||||
}
|
}
|
||||||
actual fun toast(string: String, length: Length) {
|
actual fun toast(string: String, length: Length) {
|
||||||
|
GlobalScope.launchDefault {
|
||||||
|
_toasts.emit(string to length)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,16 +6,8 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.uicore.resources
|
package ca.gosyer.jui.uicore.resources
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import dev.icerock.moko.resources.desc.PluralFormattedStringDesc
|
||||||
import dev.icerock.moko.resources.PluralsResource
|
import dev.icerock.moko.resources.desc.PluralStringDesc
|
||||||
import dev.icerock.moko.resources.desc.Plural
|
|
||||||
import dev.icerock.moko.resources.desc.PluralFormatted
|
|
||||||
import dev.icerock.moko.resources.desc.StringDesc
|
|
||||||
|
|
||||||
@Composable
|
actual fun PluralStringDesc.localized(): String = localized()
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int): String =
|
actual fun PluralFormattedStringDesc.localized() = localized()
|
||||||
StringDesc.Plural(resource, quantity).localized()
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int, vararg args: Any): String =
|
|
||||||
StringDesc.PluralFormatted(resource, quantity, *args).localized()
|
|
||||||
@@ -6,16 +6,8 @@
|
|||||||
|
|
||||||
package ca.gosyer.jui.uicore.resources
|
package ca.gosyer.jui.uicore.resources
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import dev.icerock.moko.resources.desc.PluralFormattedStringDesc
|
||||||
import dev.icerock.moko.resources.PluralsResource
|
import dev.icerock.moko.resources.desc.PluralStringDesc
|
||||||
import dev.icerock.moko.resources.desc.Plural
|
|
||||||
import dev.icerock.moko.resources.desc.PluralFormatted
|
|
||||||
import dev.icerock.moko.resources.desc.StringDesc
|
|
||||||
|
|
||||||
@Composable
|
actual fun PluralStringDesc.localized(): String = localized()
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int): String =
|
actual fun PluralFormattedStringDesc.localized() = localized()
|
||||||
StringDesc.Plural(resource, quantity).localized()
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
actual fun stringResource(resource: PluralsResource, quantity: Int, vararg args: Any): String =
|
|
||||||
StringDesc.PluralFormatted(resource, quantity, *args).localized()
|
|
||||||
|
|||||||
Reference in New Issue
Block a user