diff --git a/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt b/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt index 912622b6..b3ed7922 100644 --- a/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt +++ b/src/main/kotlin/ca/gosyer/data/server/ServerPreferences.kt @@ -16,6 +16,14 @@ class ServerPreferences(private val preferenceStore: PreferenceStore) { } fun server(): Preference { - return preferenceStore.getString("server_url", "http://localhost:4567") + return preferenceStore.getString("server_url", "http://localhost") + } + + fun port(): Preference { + return preferenceStore.getInt("server_port", 4567) + } + + fun serverUrl(): Preference { + return ServerUrlPreference("", server(), port()) } } diff --git a/src/main/kotlin/ca/gosyer/data/server/ServerUrlPreference.kt b/src/main/kotlin/ca/gosyer/data/server/ServerUrlPreference.kt new file mode 100644 index 00000000..de22d82a --- /dev/null +++ b/src/main/kotlin/ca/gosyer/data/server/ServerUrlPreference.kt @@ -0,0 +1,58 @@ +/* + * 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.data.server + +import ca.gosyer.common.prefs.Preference +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.stateIn + +class ServerUrlPreference( + private val key: String, + private val server: Preference, + private val port: Preference +) : Preference { + override fun key(): String { + return key + } + + override fun get(): String { + return server.get() + ":" + port.get() + } + + override fun set(value: String) { + val (server, port) = value.split(':') + this.server.set(server) + this.port.set(port.toInt()) + } + + override fun isSet(): Boolean { + return server.isSet() || port.isSet() + } + + override fun delete() { + server.delete() + port.delete() + } + + override fun defaultValue(): String { + return server.defaultValue() + ":" + port.defaultValue() + } + + override fun changes(): Flow { + return merge(server.changes(), port.changes()) + .map { get() } + } + + override fun stateIn(scope: CoroutineScope): StateFlow { + return changes().stateIn(scope, SharingStarted.Eagerly, get()) + } +} diff --git a/src/main/kotlin/ca/gosyer/data/server/interactions/BaseInteractionHandler.kt b/src/main/kotlin/ca/gosyer/data/server/interactions/BaseInteractionHandler.kt index 4309465e..4f928b15 100644 --- a/src/main/kotlin/ca/gosyer/data/server/interactions/BaseInteractionHandler.kt +++ b/src/main/kotlin/ca/gosyer/data/server/interactions/BaseInteractionHandler.kt @@ -22,7 +22,7 @@ open class BaseInteractionHandler( protected val client: Http, serverPreferences: ServerPreferences ) { - private val _serverUrl = serverPreferences.server() + private val _serverUrl = serverPreferences.serverUrl() val serverUrl get() = _serverUrl.get() protected inline fun repeat(block: () -> T): T { diff --git a/src/main/kotlin/ca/gosyer/ui/base/prefs/IntStringPreference.kt b/src/main/kotlin/ca/gosyer/ui/base/prefs/IntStringPreference.kt new file mode 100644 index 00000000..35118c62 --- /dev/null +++ b/src/main/kotlin/ca/gosyer/ui/base/prefs/IntStringPreference.kt @@ -0,0 +1,53 @@ +/* + * 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 ca.gosyer.common.prefs.Preference +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +fun Preference.asStringStateIn(scope: CoroutineScope): PreferenceMutableStateFlow { + return PreferenceMutableStateFlow(IntStringPreference(this), scope) +} + +class IntStringPreference(private val int: Preference) : Preference { + override fun key(): String { + return int.key() + } + + override fun get(): String { + return int.get().toString() + } + + override fun set(value: String) { + value.toIntOrNull()?.let { int.set(it) } + } + + override fun isSet(): Boolean { + return int.isSet() + } + + override fun delete() { + int.delete() + } + + override fun defaultValue(): String { + return int.defaultValue().toString() + } + + override fun changes(): Flow { + return int.changes().map { it.toString() } + } + + override fun stateIn(scope: CoroutineScope): StateFlow { + return changes().stateIn(scope, SharingStarted.Eagerly, get()) + } +} diff --git a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt index d1b496ab..bd76f91e 100644 --- a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt @@ -23,7 +23,7 @@ class ExtensionsMenuViewModel @Inject constructor( serverPreferences: ServerPreferences, private val extensionPreferences: ExtensionPreferences ) : ViewModel() { - val serverUrl = serverPreferences.server().stateIn(scope) + val serverUrl = serverPreferences.serverUrl().stateIn(scope) private lateinit var extensionList: List diff --git a/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt b/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt index 8f682e06..dc20dc82 100644 --- a/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/library/LibraryScreenViewModel.kt @@ -36,7 +36,7 @@ class LibraryScreenViewModel @Inject constructor( libraryPreferences: LibraryPreferences, serverPreferences: ServerPreferences, ) : ViewModel() { - val serverUrl = serverPreferences.server().stateIn(scope) + val serverUrl = serverPreferences.serverUrl().stateIn(scope) private val library = Library(MutableStateFlow(emptyList()), mutableMapOf()) val categories = library.categories.asStateFlow() diff --git a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt index 8ee7c4d3..7c6cba11 100644 --- a/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/manga/MangaMenuViewModel.kt @@ -35,7 +35,7 @@ class MangaMenuViewModel @Inject constructor( private val libraryHandler: LibraryInteractionHandler, serverPreferences: ServerPreferences ) : ViewModel() { - val serverUrl = serverPreferences.server().stateIn(scope) + val serverUrl = serverPreferences.serverUrl().stateIn(scope) private val _manga = MutableStateFlow(null) val manga = _manga.asStateFlow() diff --git a/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt b/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt index 128f4ee3..776d9d07 100644 --- a/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt +++ b/src/main/kotlin/ca/gosyer/ui/settings/SettingsServerScreen.kt @@ -15,6 +15,7 @@ import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.prefs.EditTextPreference import ca.gosyer.ui.base.prefs.SwitchPreference import ca.gosyer.ui.base.prefs.asStateIn +import ca.gosyer.ui.base.prefs.asStringStateIn import ca.gosyer.ui.base.vm.ViewModel import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.ui.main.Route @@ -25,7 +26,8 @@ class SettingsServerViewModel @Inject constructor( private val serverPreferences: ServerPreferences ) : ViewModel() { val host = serverPreferences.host().asStateIn(scope) - val serverUrl = serverPreferences.server().asStateIn(scope) + val server = serverPreferences.server().asStateIn(scope) + val port = serverPreferences.port().asStringStateIn(scope) } @Composable @@ -36,7 +38,10 @@ fun SettingsServerScreen(navController: BackStack) { SwitchPreference(preference = vm.host, title = "Host server inside TachideskJUI") LazyColumn { item { - EditTextPreference(vm.serverUrl, "Server Url", subtitle = vm.serverUrl.collectAsState().value) + EditTextPreference(vm.server, "Server Url", subtitle = vm.server.collectAsState().value) + } + item { + EditTextPreference(vm.port, "Server Url", subtitle = vm.port.collectAsState().value) } } } diff --git a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt index a1fa5154..01f914b1 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/SourcesMenuViewModel.kt @@ -28,7 +28,7 @@ class SourcesMenuViewModel @Inject constructor( serverPreferences: ServerPreferences, catalogPreferences: CatalogPreferences ) : ViewModel() { - val serverUrl = serverPreferences.server().stateIn(scope) + val serverUrl = serverPreferences.serverUrl().stateIn(scope) private val languages = catalogPreferences.languages().stateIn(scope) diff --git a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt index b317b2b6..d11b1b35 100644 --- a/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/sources/components/SourceScreenViewModel.kt @@ -32,7 +32,7 @@ class SourceScreenViewModel @Inject constructor( private lateinit var source: Source private var bundle: Bundle? = null - val serverUrl = serverPreferences.server().stateIn(scope) + val serverUrl = serverPreferences.serverUrl().stateIn(scope) private val _mangas = MutableStateFlow(emptyList()) val mangas = _mangas.asStateFlow()