mirror of
https://github.com/Suwayomi/TachideskJUI.git
synced 2025-12-15 17:22:03 +01:00
Support translation off the app(for the most part)
This commit is contained in:
@@ -42,6 +42,11 @@ dependencies {
|
|||||||
// Json
|
// Json
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
|
||||||
|
|
||||||
|
// Xml
|
||||||
|
val xmlutilVersion = "0.82.0"
|
||||||
|
implementation("io.github.pdvrieze.xmlutil:core-jvm:$xmlutilVersion")
|
||||||
|
implementation("io.github.pdvrieze.xmlutil:serialization-jvm:$xmlutilVersion")
|
||||||
|
|
||||||
// Dependency Injection
|
// Dependency Injection
|
||||||
val toothpickVersion = "3.1.0"
|
val toothpickVersion = "3.1.0"
|
||||||
implementation("com.github.stephanenicolas.toothpick:ktp:$toothpickVersion")
|
implementation("com.github.stephanenicolas.toothpick:ktp:$toothpickVersion")
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import ca.gosyer.data.server.interactions.ExtensionInteractionHandler
|
|||||||
import ca.gosyer.data.server.interactions.LibraryInteractionHandler
|
import ca.gosyer.data.server.interactions.LibraryInteractionHandler
|
||||||
import ca.gosyer.data.server.interactions.MangaInteractionHandler
|
import ca.gosyer.data.server.interactions.MangaInteractionHandler
|
||||||
import ca.gosyer.data.server.interactions.SourceInteractionHandler
|
import ca.gosyer.data.server.interactions.SourceInteractionHandler
|
||||||
|
import ca.gosyer.data.translation.ResourceProvider
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
import ca.gosyer.data.ui.UiPreferences
|
import ca.gosyer.data.ui.UiPreferences
|
||||||
import toothpick.ktp.binding.bind
|
import toothpick.ktp.binding.bind
|
||||||
import toothpick.ktp.binding.module
|
import toothpick.ktp.binding.module
|
||||||
@@ -60,6 +62,10 @@ val DataModule = module {
|
|||||||
.toProvider(HttpProvider::class)
|
.toProvider(HttpProvider::class)
|
||||||
.providesSingleton()
|
.providesSingleton()
|
||||||
|
|
||||||
|
bind<XmlResourceBundle>()
|
||||||
|
.toProvider(ResourceProvider::class)
|
||||||
|
.providesSingleton()
|
||||||
|
|
||||||
bind<BackupInteractionHandler>()
|
bind<BackupInteractionHandler>()
|
||||||
.toClass<BackupInteractionHandler>()
|
.toClass<BackupInteractionHandler>()
|
||||||
bind<CategoryInteractionHandler>()
|
bind<CategoryInteractionHandler>()
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class Direction(val res: String) {
|
enum class Direction(val res: String) {
|
||||||
Down("Down"),
|
Down("dir_down"),
|
||||||
Left("RTL"),
|
Left("dir_rtl"),
|
||||||
Right("LTR"),
|
Right("dir_ltr"),
|
||||||
Up("Up")
|
Up("dir_up")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class ImageScale(val res: String) {
|
enum class ImageScale(val res: String) {
|
||||||
FitScreen("Fit Screen"),
|
FitScreen("scale_fit_screen"),
|
||||||
Stretch("Strech"),
|
Stretch("scale_stretch"),
|
||||||
FitWidth("Fit Width"),
|
FitWidth("scale_fit_width"),
|
||||||
FitHeight("Fit Height"),
|
FitHeight("scale_fit_height"),
|
||||||
OriginalSize("Original Size"),
|
OriginalSize("scale_original"),
|
||||||
SmartFit("Smart Fit"),
|
SmartFit("scale_smart"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
enum class NavigationMode(val res: String) {
|
enum class NavigationMode(val res: String) {
|
||||||
LNavigation("L shaped"),
|
LNavigation("nav_l_shaped"),
|
||||||
KindlishNavigation("Kindle-ish"),
|
KindlishNavigation("nav_kindle_ish"),
|
||||||
EdgeNavigation("Edge"),
|
EdgeNavigation("nav_edge"),
|
||||||
RightAndLeftNavigation("Right and Left"),
|
RightAndLeftNavigation("nav_left_right"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.data.translation
|
||||||
|
|
||||||
|
import ca.gosyer.data.ui.UiPreferences
|
||||||
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
|
||||||
|
class ResourceProvider @Inject constructor(
|
||||||
|
val uiPreferences: UiPreferences
|
||||||
|
) : Provider<XmlResourceBundle> {
|
||||||
|
override fun get(): XmlResourceBundle {
|
||||||
|
val languagePref = uiPreferences.language()
|
||||||
|
return if (languagePref.isSet()) {
|
||||||
|
languagePref.get().let {
|
||||||
|
val locale: Locale? = Locale.forLanguageTag(it)
|
||||||
|
if (locale != null) {
|
||||||
|
XmlResourceBundle.forLocale(locale)
|
||||||
|
} else {
|
||||||
|
XmlResourceBundle.forTag(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else XmlResourceBundle.forLocale(Locale.getDefault())
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/main/kotlin/ca/gosyer/data/translation/XmlResourceBundle.kt
Normal file
115
src/main/kotlin/ca/gosyer/data/translation/XmlResourceBundle.kt
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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.translation
|
||||||
|
|
||||||
|
import ca.gosyer.data.translation.xml.Resources
|
||||||
|
import nl.adaptivity.xmlutil.StAXReader
|
||||||
|
import nl.adaptivity.xmlutil.serialization.XML
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.io.Reader
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.Enumeration
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.ResourceBundle
|
||||||
|
|
||||||
|
class XmlResourceBundle internal constructor(internal val lookup: Map<String, Any>) : ResourceBundle() {
|
||||||
|
|
||||||
|
constructor(stream: InputStream, charset: Charset = Charsets.UTF_8) : this(
|
||||||
|
stream.reader(charset)
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(reader: Reader) : this(
|
||||||
|
format.decodeFromReader<Resources>(
|
||||||
|
StAXReader(reader)
|
||||||
|
).values.associate { it.name to it.value }
|
||||||
|
)
|
||||||
|
|
||||||
|
public override fun handleGetObject(key: String): Any? {
|
||||||
|
return lookup[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getKeys(): Enumeration<String> {
|
||||||
|
return Collections.enumeration(keySet())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleKeySet(): Set<String> {
|
||||||
|
return lookup.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun plus(other: XmlResourceBundle): XmlResourceBundle {
|
||||||
|
return XmlResourceBundle(lookup + other.lookup)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStringA(key: String): String {
|
||||||
|
return getString(key).replace("\\n", "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getString(key: String, vararg replacements: String): String {
|
||||||
|
var string = getStringA(key)
|
||||||
|
replacements.forEachIndexed { index, s ->
|
||||||
|
string = string.replace(
|
||||||
|
"%" + (index + 1).toString() + '$' + "s",
|
||||||
|
s
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val format by lazy {
|
||||||
|
XML {
|
||||||
|
autoPolymorphic = true
|
||||||
|
indentString = "\t"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forTag(tag: String): XmlResourceBundle {
|
||||||
|
val classLoader = this::class.java.classLoader
|
||||||
|
val rootBundle = classLoader.getResourceAsStream("values/values/strings.xml")!!
|
||||||
|
.use { XmlResourceBundle(it) }
|
||||||
|
|
||||||
|
val languageBundle = classLoader.getResourceAsStream("values/values-${tag.substringBefore('-')}/strings.xml")
|
||||||
|
?.use { XmlResourceBundle(it) }
|
||||||
|
|
||||||
|
val languageTagBundle = if (tag.contains('-')) {
|
||||||
|
classLoader.getResourceAsStream("values/values-$tag/strings.xml")
|
||||||
|
?.use { XmlResourceBundle(it) }
|
||||||
|
} else null
|
||||||
|
|
||||||
|
var resultBundle = rootBundle
|
||||||
|
if (languageBundle != null) {
|
||||||
|
resultBundle += languageBundle
|
||||||
|
}
|
||||||
|
if (languageTagBundle != null) {
|
||||||
|
resultBundle += languageTagBundle
|
||||||
|
}
|
||||||
|
return resultBundle
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forLocale(locale: Locale): XmlResourceBundle {
|
||||||
|
val classLoader = this::class.java.classLoader
|
||||||
|
val rootBundle = classLoader.getResourceAsStream("values/values/strings.xml")!!
|
||||||
|
.use { XmlResourceBundle(it) }
|
||||||
|
|
||||||
|
val languageBundle = classLoader.getResourceAsStream("values/values-${locale.language}/strings.xml")
|
||||||
|
?.use { XmlResourceBundle(it) }
|
||||||
|
|
||||||
|
val languageTagBundle = classLoader.getResourceAsStream("values/values-${locale.toLanguageTag()}/strings.xml")
|
||||||
|
?.use { XmlResourceBundle(it) }
|
||||||
|
|
||||||
|
var resultBundle = rootBundle
|
||||||
|
if (languageBundle != null) {
|
||||||
|
resultBundle += languageBundle
|
||||||
|
}
|
||||||
|
if (languageTagBundle != null) {
|
||||||
|
resultBundle += languageTagBundle
|
||||||
|
}
|
||||||
|
return resultBundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/main/kotlin/ca/gosyer/data/translation/xml/Resources.kt
Normal file
14
src/main/kotlin/ca/gosyer/data/translation/xml/Resources.kt
Normal file
@@ -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.data.translation.xml
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import nl.adaptivity.xmlutil.serialization.XmlSerialName
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@XmlSerialName("resources", "", "")
|
||||||
|
data class Resources(val values: List<XmlString>)
|
||||||
21
src/main/kotlin/ca/gosyer/data/translation/xml/XmlString.kt
Normal file
21
src/main/kotlin/ca/gosyer/data/translation/xml/XmlString.kt
Normal file
@@ -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.data.translation.xml
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import nl.adaptivity.xmlutil.serialization.XmlElement
|
||||||
|
import nl.adaptivity.xmlutil.serialization.XmlSerialName
|
||||||
|
import nl.adaptivity.xmlutil.serialization.XmlValue
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@XmlSerialName("string", "", "")
|
||||||
|
data class XmlString(
|
||||||
|
@XmlElement(false)
|
||||||
|
val name: String,
|
||||||
|
@XmlValue(true)
|
||||||
|
val value: String
|
||||||
|
)
|
||||||
@@ -21,6 +21,7 @@ import androidx.compose.material.OutlinedButton
|
|||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.key.Key
|
import androidx.compose.ui.input.key.Key
|
||||||
@@ -28,6 +29,9 @@ import androidx.compose.ui.input.key.KeysSet
|
|||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ca.gosyer.common.di.AppScope
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
|
import ca.gosyer.ui.base.resources.LocalResources
|
||||||
import ca.gosyer.ui.base.theme.AppTheme
|
import ca.gosyer.ui.base.theme.AppTheme
|
||||||
import ca.gosyer.util.lang.launchUI
|
import ca.gosyer.util.lang.launchUI
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
@@ -77,28 +81,34 @@ fun WindowDialog(
|
|||||||
window.keyboard.setShortcut(it.key) { it.shortcut(window) }
|
window.keyboard.setShortcut(it.key) { it.shortcut(window) }
|
||||||
}
|
}
|
||||||
|
|
||||||
window.show {
|
val resources = AppScope.getInstance<XmlResourceBundle>()
|
||||||
AppTheme {
|
|
||||||
Surface {
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
|
||||||
Row(
|
|
||||||
content = row,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.Bottom,
|
|
||||||
horizontalArrangement = Arrangement.End,
|
|
||||||
modifier = Modifier.height(70.dp)
|
|
||||||
.align(Alignment.BottomEnd)
|
|
||||||
) {
|
|
||||||
if (showNegativeButton) {
|
|
||||||
OutlinedButton(onNegativeButton.plusClose(), modifier = Modifier.padding(end = 8.dp, bottom = 8.dp)) {
|
|
||||||
Text(negativeButtonText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OutlinedButton(onPositiveButton.plusClose(), modifier = Modifier.padding(end = 8.dp, bottom = 8.dp)) {
|
window.show {
|
||||||
Text(positiveButtonText)
|
CompositionLocalProvider(
|
||||||
|
LocalResources provides resources
|
||||||
|
) {
|
||||||
|
AppTheme {
|
||||||
|
Surface {
|
||||||
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
|
Row(
|
||||||
|
content = row,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.Bottom,
|
||||||
|
horizontalArrangement = Arrangement.End,
|
||||||
|
modifier = Modifier.height(70.dp)
|
||||||
|
.align(Alignment.BottomEnd)
|
||||||
|
) {
|
||||||
|
if (showNegativeButton) {
|
||||||
|
OutlinedButton(onNegativeButton.plusClose(), modifier = Modifier.padding(end = 8.dp, bottom = 8.dp)) {
|
||||||
|
Text(negativeButtonText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OutlinedButton(onPositiveButton.plusClose(), modifier = Modifier.padding(end = 8.dp, bottom = 8.dp)) {
|
||||||
|
Text(positiveButtonText)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,14 +149,20 @@ fun WindowDialog(
|
|||||||
window.keyboard.setShortcut(it.key) { it.shortcut(window) }
|
window.keyboard.setShortcut(it.key) { it.shortcut(window) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val resources = AppScope.getInstance<XmlResourceBundle>()
|
||||||
|
|
||||||
window.show {
|
window.show {
|
||||||
AppTheme {
|
CompositionLocalProvider(
|
||||||
Surface {
|
LocalResources provides resources
|
||||||
Column(
|
) {
|
||||||
modifier = Modifier.fillMaxSize()
|
AppTheme {
|
||||||
) {
|
Surface {
|
||||||
content(window)
|
Column(
|
||||||
buttons(window)
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
content(window)
|
||||||
|
buttons(window)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.ui.base.resources
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
|
|
||||||
|
val LocalResources: ProvidableCompositionLocal<XmlResourceBundle> =
|
||||||
|
compositionLocalOf { throw IllegalStateException("resources have not been not initialized") }
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun stringResource(key: String): String {
|
||||||
|
val resources = LocalResources.current
|
||||||
|
return remember(key) { resources.getStringA(key) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun stringResource(key: String, vararg replacements: String): String {
|
||||||
|
val resources = LocalResources.current
|
||||||
|
return remember(key, replacements) { resources.getString(key, *replacements) }
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ import androidx.compose.runtime.collectAsState
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import ca.gosyer.ui.base.WindowDialog
|
import ca.gosyer.ui.base.WindowDialog
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
||||||
fun openRenameDialog(
|
fun openRenameDialog(
|
||||||
@@ -52,7 +53,7 @@ fun openDeleteDialog(
|
|||||||
},
|
},
|
||||||
negativeButtonText = "No"
|
negativeButtonText = "No"
|
||||||
) {
|
) {
|
||||||
Text("Do you wish to delete the category ${category.name}?")
|
Text(stringResource("categories_delete_confirm", category.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import ca.gosyer.BuildConfig
|
import ca.gosyer.BuildConfig
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.util.compose.ThemedWindow
|
import ca.gosyer.util.compose.ThemedWindow
|
||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
@@ -103,7 +104,7 @@ fun CategoriesMenu(notifyFinished: (() -> Unit)? = null, windowEvents: WindowEve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = { Text(text = "Add") },
|
text = { Text(text = stringResource("action_add")) },
|
||||||
icon = { Icon(imageVector = Icons.Default.Add, contentDescription = null) },
|
icon = { Icon(imageVector = Icons.Default.Add, contentDescription = null) },
|
||||||
modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp),
|
modifier = Modifier.align(Alignment.BottomEnd).padding(16.dp),
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import ca.gosyer.data.models.Chapter
|
|||||||
import ca.gosyer.ui.base.components.ActionIcon
|
import ca.gosyer.ui.base.components.ActionIcon
|
||||||
import ca.gosyer.ui.base.components.DropdownIconButton
|
import ca.gosyer.ui.base.components.DropdownIconButton
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.util.compose.ThemedWindow
|
import ca.gosyer.util.compose.ThemedWindow
|
||||||
|
|
||||||
@@ -62,16 +63,16 @@ fun DownloadsMenu() {
|
|||||||
Surface {
|
Surface {
|
||||||
Column {
|
Column {
|
||||||
Toolbar(
|
Toolbar(
|
||||||
"Downloads",
|
stringResource("location_downloads"),
|
||||||
closable = false,
|
closable = false,
|
||||||
actions = {
|
actions = {
|
||||||
val downloadStatus by vm.downloaderStatus.collectAsState()
|
val downloadStatus by vm.downloaderStatus.collectAsState()
|
||||||
if (downloadStatus == DownloaderStatus.Started) {
|
if (downloadStatus == DownloaderStatus.Started) {
|
||||||
ActionIcon(onClick = vm::pause, "Pause", Icons.Default.Pause)
|
ActionIcon(onClick = vm::pause, stringResource("action_pause"), Icons.Default.Pause)
|
||||||
} else {
|
} else {
|
||||||
ActionIcon(onClick = vm::start, "Continue", Icons.Default.PlayArrow)
|
ActionIcon(onClick = vm::start, stringResource("action_continue"), Icons.Default.PlayArrow)
|
||||||
}
|
}
|
||||||
ActionIcon(onClick = vm::clear, "Clear queue", Icons.Default.ClearAll)
|
ActionIcon(onClick = vm::clear, stringResource("action_clear_queue"), Icons.Default.ClearAll)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
LazyColumn(Modifier.fillMaxSize()) {
|
LazyColumn(Modifier.fillMaxSize()) {
|
||||||
@@ -137,10 +138,10 @@ private fun downloadsItem(
|
|||||||
chapter.mangaId to chapter.chapterIndex,
|
chapter.mangaId to chapter.chapterIndex,
|
||||||
{
|
{
|
||||||
DropdownMenuItem(onClick = { onDownloadCancel(chapter.chapter) }) {
|
DropdownMenuItem(onClick = { onDownloadCancel(chapter.chapter) }) {
|
||||||
Text("Cancel")
|
Text(stringResource("action_cancel"))
|
||||||
}
|
}
|
||||||
DropdownMenuItem(onClick = { onMoveDownloadToBottom(chapter.chapter) }) {
|
DropdownMenuItem(onClick = { onMoveDownloadToBottom(chapter.chapter) }) {
|
||||||
Text("Move to bottom")
|
Text(stringResource("action_move_to_bottom"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import ca.gosyer.ui.base.components.ActionIcon
|
|||||||
import ca.gosyer.ui.base.components.KtorImage
|
import ca.gosyer.ui.base.components.KtorImage
|
||||||
import ca.gosyer.ui.base.components.LoadingScreen
|
import ca.gosyer.ui.base.components.LoadingScreen
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.util.compose.ThemedWindow
|
import ca.gosyer.util.compose.ThemedWindow
|
||||||
import ca.gosyer.util.compose.persistentLazyListState
|
import ca.gosyer.util.compose.persistentLazyListState
|
||||||
@@ -82,7 +83,7 @@ fun ExtensionsMenu() {
|
|||||||
LazyColumn(Modifier.fillMaxSize().padding(end = 12.dp), state) {
|
LazyColumn(Modifier.fillMaxSize().padding(end = 12.dp), state) {
|
||||||
item {
|
item {
|
||||||
Toolbar(
|
Toolbar(
|
||||||
"Extensions",
|
stringResource("location_extensions"),
|
||||||
closable = false,
|
closable = false,
|
||||||
searchText = search,
|
searchText = search,
|
||||||
search = {
|
search = {
|
||||||
@@ -96,7 +97,7 @@ fun ExtensionsMenu() {
|
|||||||
vm.setEnabledLanguages(enabledLangs.value)
|
vm.setEnabledLanguages(enabledLangs.value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Enabled languages",
|
stringResource("enabled_languages"),
|
||||||
Icons.Default.Translate
|
Icons.Default.Translate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -167,9 +168,9 @@ fun ExtensionItem(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
when {
|
when {
|
||||||
extension.hasUpdate -> "Update"
|
extension.hasUpdate -> stringResource("action_update")
|
||||||
extension.installed -> "Uninstall"
|
extension.installed -> stringResource("action_uninstall")
|
||||||
else -> "Install"
|
else -> stringResource("action_install")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -178,6 +179,7 @@ fun ExtensionItem(
|
|||||||
|
|
||||||
fun LanguageDialog(enabledLangsFlow: MutableStateFlow<Set<String>>, availableLangs: List<String>, setLangs: () -> Unit) {
|
fun LanguageDialog(enabledLangsFlow: MutableStateFlow<Set<String>>, availableLangs: List<String>, setLangs: () -> Unit) {
|
||||||
WindowDialog(BuildConfig.NAME, onPositiveButton = setLangs) {
|
WindowDialog(BuildConfig.NAME, onPositiveButton = setLangs) {
|
||||||
|
val locale = Locale.getDefault()
|
||||||
val enabledLangs by enabledLangsFlow.collectAsState()
|
val enabledLangs by enabledLangsFlow.collectAsState()
|
||||||
val state = rememberLazyListState()
|
val state = rememberLazyListState()
|
||||||
Box {
|
Box {
|
||||||
@@ -185,7 +187,7 @@ fun LanguageDialog(enabledLangsFlow: MutableStateFlow<Set<String>>, availableLan
|
|||||||
items(availableLangs) { lang ->
|
items(availableLangs) { lang ->
|
||||||
Row {
|
Row {
|
||||||
val langName = remember(lang) {
|
val langName = remember(lang) {
|
||||||
Locale.forLanguageTag(lang)?.displayName ?: lang
|
Locale.forLanguageTag(lang)?.getDisplayName(locale) ?: lang
|
||||||
}
|
}
|
||||||
Text(langName)
|
Text(langName)
|
||||||
Switch(
|
Switch(
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import ca.gosyer.data.models.Manga
|
|||||||
import ca.gosyer.data.server.ServerPreferences
|
import ca.gosyer.data.server.ServerPreferences
|
||||||
import ca.gosyer.data.server.interactions.CategoryInteractionHandler
|
import ca.gosyer.data.server.interactions.CategoryInteractionHandler
|
||||||
import ca.gosyer.data.server.interactions.LibraryInteractionHandler
|
import ca.gosyer.data.server.interactions.LibraryInteractionHandler
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
import ca.gosyer.ui.base.vm.ViewModel
|
import ca.gosyer.ui.base.vm.ViewModel
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@@ -33,6 +34,7 @@ private fun LibraryMap.setManga(order: Int, manga: List<Manga>) {
|
|||||||
class LibraryScreenViewModel @Inject constructor(
|
class LibraryScreenViewModel @Inject constructor(
|
||||||
private val libraryHandler: LibraryInteractionHandler,
|
private val libraryHandler: LibraryInteractionHandler,
|
||||||
private val categoryHandler: CategoryInteractionHandler,
|
private val categoryHandler: CategoryInteractionHandler,
|
||||||
|
private val resources: XmlResourceBundle,
|
||||||
libraryPreferences: LibraryPreferences,
|
libraryPreferences: LibraryPreferences,
|
||||||
serverPreferences: ServerPreferences,
|
serverPreferences: ServerPreferences,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
@@ -49,6 +51,8 @@ class LibraryScreenViewModel @Inject constructor(
|
|||||||
private val _isLoading = MutableStateFlow(true)
|
private val _isLoading = MutableStateFlow(true)
|
||||||
val isLoading = _isLoading.asStateFlow()
|
val isLoading = _isLoading.asStateFlow()
|
||||||
|
|
||||||
|
private val defaultCategory = Category(0, 0, resources.getStringA("default_category"), true)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
getLibrary()
|
getLibrary()
|
||||||
}
|
}
|
||||||
@@ -85,8 +89,4 @@ class LibraryScreenViewModel @Inject constructor(
|
|||||||
fun getLibraryForCategoryIndex(index: Int): StateFlow<List<Manga>> {
|
fun getLibraryForCategoryIndex(index: Int): StateFlow<List<Manga>> {
|
||||||
return library.mangaMap.getManga(index).asStateFlow()
|
return library.mangaMap.getManga(index).asStateFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
val defaultCategory = Category(0, 0, "Default", true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import ca.gosyer.BuildConfig
|
import ca.gosyer.BuildConfig
|
||||||
import ca.gosyer.data.ui.model.StartScreen
|
import ca.gosyer.data.ui.model.StartScreen
|
||||||
import ca.gosyer.ui.base.components.combinedMouseClickable
|
import ca.gosyer.ui.base.components.combinedMouseClickable
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.downloads.DownloadsMenu
|
import ca.gosyer.ui.downloads.DownloadsMenu
|
||||||
import ca.gosyer.ui.downloads.DownloadsMenuViewModel
|
import ca.gosyer.ui.downloads.DownloadsMenuViewModel
|
||||||
@@ -125,7 +126,7 @@ fun SideMenu(backStack: BackStack<Route>) {
|
|||||||
fun SideMenuItem(topLevelMenu: TopLevelMenus, backStack: BackStack<Route>) {
|
fun SideMenuItem(topLevelMenu: TopLevelMenus, backStack: BackStack<Route>) {
|
||||||
MainMenuItem(
|
MainMenuItem(
|
||||||
backStack.elements.first() == topLevelMenu.menu,
|
backStack.elements.first() == topLevelMenu.menu,
|
||||||
topLevelMenu.text,
|
stringResource(topLevelMenu.textKey),
|
||||||
topLevelMenu.menu,
|
topLevelMenu.menu,
|
||||||
topLevelMenu.selectedIcon,
|
topLevelMenu.selectedIcon,
|
||||||
topLevelMenu.unselectedIcon,
|
topLevelMenu.unselectedIcon,
|
||||||
@@ -233,7 +234,7 @@ fun DownloadsExtraInfo() {
|
|||||||
val list by vm.downloadQueue.collectAsState()
|
val list by vm.downloadQueue.collectAsState()
|
||||||
if (list.isNotEmpty()) {
|
if (list.isNotEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
"${list.size} remaining",
|
stringResource("downloads_remaining", list.size.toString()),
|
||||||
style = MaterialTheme.typography.body2,
|
style = MaterialTheme.typography.body2,
|
||||||
color = LocalContentColor.current.copy(alpha = ContentAlpha.disabled)
|
color = LocalContentColor.current.copy(alpha = ContentAlpha.disabled)
|
||||||
)
|
)
|
||||||
@@ -241,7 +242,7 @@ fun DownloadsExtraInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class TopLevelMenus(
|
enum class TopLevelMenus(
|
||||||
val text: String,
|
val textKey: String,
|
||||||
val unselectedIcon: ImageVector,
|
val unselectedIcon: ImageVector,
|
||||||
val selectedIcon: ImageVector,
|
val selectedIcon: ImageVector,
|
||||||
val menu: Route,
|
val menu: Route,
|
||||||
@@ -249,11 +250,11 @@ enum class TopLevelMenus(
|
|||||||
val openInNewWindow: () -> Unit = {},
|
val openInNewWindow: () -> Unit = {},
|
||||||
val extraInfo: (@Composable () -> Unit)? = null
|
val extraInfo: (@Composable () -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
Library("Library", Icons.Outlined.Book, Icons.Filled.Book, Route.Library, true, ::openLibraryMenu),
|
Library("location_library", Icons.Outlined.Book, Icons.Filled.Book, Route.Library, true, ::openLibraryMenu),
|
||||||
Sources("Sources", Icons.Outlined.Explore, Icons.Filled.Explore, Route.Sources, true, ::openSourcesMenu),
|
Sources("location_sources", Icons.Outlined.Explore, Icons.Filled.Explore, Route.Sources, true, ::openSourcesMenu),
|
||||||
Extensions("Extensions", Icons.Outlined.Store, Icons.Filled.Store, Route.Extensions, true, ::openExtensionsMenu),
|
Extensions("location_extensions", Icons.Outlined.Store, Icons.Filled.Store, Route.Extensions, true, ::openExtensionsMenu),
|
||||||
Downloads("Downloads", Icons.Outlined.Download, Icons.Filled.Download, Route.Downloads, false, extraInfo = { DownloadsExtraInfo() }),
|
Downloads("location_downloads", Icons.Outlined.Download, Icons.Filled.Download, Route.Downloads, false, extraInfo = { DownloadsExtraInfo() }),
|
||||||
Settings("Settings", Icons.Outlined.Settings, Icons.Filled.Settings, Route.Settings, false)
|
Settings("location_settings", Icons.Outlined.Settings, Icons.Filled.Settings, Route.Settings, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Route {
|
sealed class Route {
|
||||||
|
|||||||
@@ -16,10 +16,13 @@ import ca.gosyer.BuildConfig
|
|||||||
import ca.gosyer.data.DataModule
|
import ca.gosyer.data.DataModule
|
||||||
import ca.gosyer.data.server.ServerService
|
import ca.gosyer.data.server.ServerService
|
||||||
import ca.gosyer.data.server.ServerService.ServerResult
|
import ca.gosyer.data.server.ServerService.ServerResult
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
import ca.gosyer.data.ui.UiPreferences
|
import ca.gosyer.data.ui.UiPreferences
|
||||||
import ca.gosyer.data.ui.model.ThemeMode
|
import ca.gosyer.data.ui.model.ThemeMode
|
||||||
import ca.gosyer.data.ui.model.WindowSettings
|
import ca.gosyer.data.ui.model.WindowSettings
|
||||||
import ca.gosyer.ui.base.components.LoadingScreen
|
import ca.gosyer.ui.base.components.LoadingScreen
|
||||||
|
import ca.gosyer.ui.base.resources.LocalResources
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.theme.AppTheme
|
import ca.gosyer.ui.base.theme.AppTheme
|
||||||
import ca.gosyer.util.lang.launchUI
|
import ca.gosyer.util.lang.launchUI
|
||||||
import ca.gosyer.util.lang.withUIContext
|
import ca.gosyer.util.lang.withUIContext
|
||||||
@@ -66,8 +69,10 @@ fun main() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val serverService = scope.getInstance<ServerService>()
|
val serverService = scope.getInstance<ServerService>()
|
||||||
|
val uiPreferences = scope.getInstance<UiPreferences>()
|
||||||
|
val resources = scope.getInstance<XmlResourceBundle>()
|
||||||
|
|
||||||
scope.getInstance<UiPreferences>().themeMode()
|
uiPreferences.themeMode()
|
||||||
.getAsFlow {
|
.getAsFlow {
|
||||||
if (System.getProperty("os.name").startsWith("Mac") && System.getProperty("os.arch") == "aarch64") {
|
if (System.getProperty("os.name").startsWith("Mac") && System.getProperty("os.arch") == "aarch64") {
|
||||||
return@getAsFlow
|
return@getAsFlow
|
||||||
@@ -89,7 +94,7 @@ fun main() {
|
|||||||
}
|
}
|
||||||
.launchIn(GlobalScope)
|
.launchIn(GlobalScope)
|
||||||
|
|
||||||
val windowSettings = scope.getInstance<UiPreferences>().window()
|
val windowSettings = uiPreferences.window()
|
||||||
val (
|
val (
|
||||||
offset,
|
offset,
|
||||||
size,
|
size,
|
||||||
@@ -129,7 +134,8 @@ fun main() {
|
|||||||
window.show {
|
window.show {
|
||||||
AppTheme {
|
AppTheme {
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
LocalBackPressHandler provides backPressHandler
|
LocalBackPressHandler provides backPressHandler,
|
||||||
|
LocalResources provides resources
|
||||||
) {
|
) {
|
||||||
val initialized by serverService.initialized.collectAsState()
|
val initialized by serverService.initialized.collectAsState()
|
||||||
when (initialized) {
|
when (initialized) {
|
||||||
@@ -139,12 +145,14 @@ fun main() {
|
|||||||
ServerResult.STARTING, ServerResult.FAILED, ServerResult.NO_TACHIDESK_JAR -> {
|
ServerResult.STARTING, ServerResult.FAILED, ServerResult.NO_TACHIDESK_JAR -> {
|
||||||
LoadingScreen(
|
LoadingScreen(
|
||||||
initialized == ServerResult.STARTING,
|
initialized == ServerResult.STARTING,
|
||||||
errorMessage = if (initialized == ServerResult.NO_TACHIDESK_JAR) {
|
errorMessage = stringResource(
|
||||||
"Tachidesk jar does not exist, run Tachidesk yourself"
|
if (initialized == ServerResult.NO_TACHIDESK_JAR) {
|
||||||
} else {
|
"tachidesk_doesnt_exist"
|
||||||
"Unable to start server"
|
} else {
|
||||||
},
|
"unable_to_start_server"
|
||||||
retryMessage = "Start anyway",
|
}
|
||||||
|
),
|
||||||
|
retryMessage = stringResource("action_start_anyway"),
|
||||||
retry = serverService::startAnyway
|
retry = serverService::startAnyway
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import ca.gosyer.data.download.model.DownloadChapter
|
|||||||
import ca.gosyer.data.download.model.DownloadState
|
import ca.gosyer.data.download.model.DownloadState
|
||||||
import ca.gosyer.ui.base.components.DropdownIconButton
|
import ca.gosyer.ui.base.components.DropdownIconButton
|
||||||
import ca.gosyer.ui.base.components.combinedMouseClickable
|
import ca.gosyer.ui.base.components.combinedMouseClickable
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.util.compose.contextMenu
|
import ca.gosyer.util.compose.contextMenu
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ fun ChapterItem(
|
|||||||
if (length > 0) append(" • ")
|
if (length > 0) append(" • ")
|
||||||
append(
|
append(
|
||||||
AnnotatedString(
|
AnnotatedString(
|
||||||
"Page " + (chapter.lastPageRead + 1).toString(),
|
stringResource("page_progress", (chapter.lastPageRead + 1).toString()),
|
||||||
SpanStyle(color = LocalContentColor.current.copy(alpha = ContentAlpha.disabled))
|
SpanStyle(color = LocalContentColor.current.copy(alpha = ContentAlpha.disabled))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -179,7 +180,7 @@ private fun DownloadingIconButton(downloadChapter: DownloadChapter?, onClick: ()
|
|||||||
downloadChapter?.mangaId to downloadChapter?.chapterIndex,
|
downloadChapter?.mangaId to downloadChapter?.chapterIndex,
|
||||||
{
|
{
|
||||||
DropdownMenuItem(onClick = onClick) {
|
DropdownMenuItem(onClick = onClick) {
|
||||||
Text("Cancel")
|
Text(stringResource("action_cancel"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -247,7 +248,7 @@ private fun DownloadedIconButton(chapter: Pair<Long, Int?>, onClick: () -> Unit)
|
|||||||
chapter,
|
chapter,
|
||||||
{
|
{
|
||||||
DropdownMenuItem(onClick = onClick) {
|
DropdownMenuItem(onClick = onClick) {
|
||||||
Text("Delete")
|
Text(stringResource("action_delete"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import ca.gosyer.ui.base.components.KtorImage
|
|||||||
import ca.gosyer.ui.base.components.LoadingScreen
|
import ca.gosyer.ui.base.components.LoadingScreen
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.components.mangaAspectRatio
|
import ca.gosyer.ui.base.components.mangaAspectRatio
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import ca.gosyer.ui.reader.openReaderMenu
|
import ca.gosyer.ui.reader.openReaderMenu
|
||||||
@@ -69,15 +70,15 @@ fun MangaMenu(mangaId: Long, backStack: BackStack<Route>? = null) {
|
|||||||
val dateTimeFormatter by vm.dateTimeFormatter.collectAsState()
|
val dateTimeFormatter by vm.dateTimeFormatter.collectAsState()
|
||||||
|
|
||||||
Column(Modifier.background(MaterialTheme.colors.background)) {
|
Column(Modifier.background(MaterialTheme.colors.background)) {
|
||||||
Toolbar("Manga", backStack, backStack != null)
|
Toolbar(stringResource("location_manga"), backStack, backStack != null)
|
||||||
|
|
||||||
Surface(Modifier.height(40.dp).fillMaxWidth()) {
|
Surface(Modifier.height(40.dp).fillMaxWidth()) {
|
||||||
Row(horizontalArrangement = Arrangement.SpaceBetween) {
|
Row(horizontalArrangement = Arrangement.SpaceBetween) {
|
||||||
Button(onClick = vm::toggleFavorite) {
|
Button(onClick = vm::toggleFavorite) {
|
||||||
Text(if (manga?.inLibrary == true) "UnFavorite" else "Favorite")
|
Text(stringResource(if (manga?.inLibrary == true) "action_remove_favorite" else "action_favorite"))
|
||||||
}
|
}
|
||||||
Button(onClick = vm::refreshManga, enabled = !vm.isRefreshing.collectAsState().value) {
|
Button(onClick = vm::refreshManga, enabled = !vm.isRefreshing.collectAsState().value) {
|
||||||
Text("Refresh manga")
|
Text(stringResource("action_refresh_manga"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -32,12 +33,15 @@ import ca.gosyer.common.di.AppScope
|
|||||||
import ca.gosyer.data.reader.model.Direction
|
import ca.gosyer.data.reader.model.Direction
|
||||||
import ca.gosyer.data.reader.model.ImageScale
|
import ca.gosyer.data.reader.model.ImageScale
|
||||||
import ca.gosyer.data.reader.model.NavigationMode
|
import ca.gosyer.data.reader.model.NavigationMode
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
import ca.gosyer.data.ui.UiPreferences
|
import ca.gosyer.data.ui.UiPreferences
|
||||||
import ca.gosyer.data.ui.model.WindowSettings
|
import ca.gosyer.data.ui.model.WindowSettings
|
||||||
import ca.gosyer.ui.base.KeyboardShortcut
|
import ca.gosyer.ui.base.KeyboardShortcut
|
||||||
import ca.gosyer.ui.base.components.ErrorScreen
|
import ca.gosyer.ui.base.components.ErrorScreen
|
||||||
import ca.gosyer.ui.base.components.LoadingScreen
|
import ca.gosyer.ui.base.components.LoadingScreen
|
||||||
import ca.gosyer.ui.base.components.mangaAspectRatio
|
import ca.gosyer.ui.base.components.mangaAspectRatio
|
||||||
|
import ca.gosyer.ui.base.resources.LocalResources
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.theme.AppTheme
|
import ca.gosyer.ui.base.theme.AppTheme
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.reader.model.Navigation
|
import ca.gosyer.ui.reader.model.Navigation
|
||||||
@@ -63,6 +67,8 @@ fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
|
|||||||
maximized
|
maximized
|
||||||
) = windowSettings.get().get()
|
) = windowSettings.get().get()
|
||||||
|
|
||||||
|
val resources = AppScope.getInstance<XmlResourceBundle>()
|
||||||
|
|
||||||
launchUI {
|
launchUI {
|
||||||
val window = AppWindow(
|
val window = AppWindow(
|
||||||
"TachideskJUI - Reader",
|
"TachideskJUI - Reader",
|
||||||
@@ -94,12 +100,16 @@ fun openReaderMenu(chapterIndex: Int, mangaId: Long) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.show {
|
window.show {
|
||||||
AppTheme {
|
CompositionLocalProvider(
|
||||||
ReaderMenu(chapterIndex, mangaId, setHotkeys) {
|
LocalResources provides resources
|
||||||
val onClose = window.events.onClose
|
) {
|
||||||
window.events.onClose = {
|
AppTheme {
|
||||||
it()
|
ReaderMenu(chapterIndex, mangaId, setHotkeys) {
|
||||||
onClose?.invoke()
|
val onClose = window.events.onClose
|
||||||
|
window.events.onClose = {
|
||||||
|
it()
|
||||||
|
onClose?.invoke()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +206,7 @@ fun ReaderMenu(chapterIndex: Int, mangaId: Long, setHotkeys: (List<KeyboardShort
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ErrorScreen("No pages found")
|
ErrorScreen(stringResource("no_pages_found"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,15 +253,15 @@ fun ChapterSeperator(
|
|||||||
Column {
|
Column {
|
||||||
when {
|
when {
|
||||||
previousChapter == null && nextChapter != null -> {
|
previousChapter == null && nextChapter != null -> {
|
||||||
Text("There is no previous chapter")
|
Text(stringResource("no_previous_chapter"))
|
||||||
}
|
}
|
||||||
previousChapter != null && nextChapter != null -> {
|
previousChapter != null && nextChapter != null -> {
|
||||||
Text("Previous:\n ${previousChapter.chapter.name}")
|
Text(stringResource("previous_chapter", previousChapter.chapter.name))
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(8.dp))
|
||||||
Text("Next:\n ${nextChapter.chapter.name}")
|
Text(stringResource("next_chapter", nextChapter.chapter.name))
|
||||||
}
|
}
|
||||||
previousChapter != null && nextChapter == null -> {
|
previousChapter != null && nextChapter == null -> {
|
||||||
Text("There is no next chapter")
|
Text(stringResource("no_next_chapter"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsAdvancedScreen(navController: BackStack<Route>) {
|
fun SettingsAdvancedScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Advanced Settings", navController, true)
|
Toolbar(stringResource("settings_advanced_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import ca.gosyer.data.ui.model.ThemeMode
|
|||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.prefs.ChoicePreference
|
import ca.gosyer.ui.base.prefs.ChoicePreference
|
||||||
import ca.gosyer.ui.base.prefs.ColorPreference
|
import ca.gosyer.ui.base.prefs.ColorPreference
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.theme.AppColorsPreferenceState
|
import ca.gosyer.ui.base.theme.AppColorsPreferenceState
|
||||||
import ca.gosyer.ui.base.theme.Theme
|
import ca.gosyer.ui.base.theme.Theme
|
||||||
import ca.gosyer.ui.base.theme.asStateFlow
|
import ca.gosyer.ui.base.theme.asStateFlow
|
||||||
@@ -73,22 +74,22 @@ fun SettingsAppearance(navController: BackStack<Route>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Appearance Settings", navController, true)
|
Toolbar(stringResource("settings_appearance_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
preference = vm.themeMode,
|
preference = vm.themeMode,
|
||||||
choices = mapOf(
|
choices = mapOf(
|
||||||
// ThemeMode.System to R.string.follow_system_settings,
|
// ThemeMode.System to R.string.follow_system_settings,
|
||||||
ThemeMode.Light to "Light",
|
ThemeMode.Light to stringResource("theme_light"),
|
||||||
ThemeMode.Dark to "Dark"
|
ThemeMode.Dark to stringResource("theme_Dark")
|
||||||
),
|
),
|
||||||
title = "Theme"
|
title = stringResource("theme")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
"Preset themes",
|
stringResource("preset_themes"),
|
||||||
modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 4.dp)
|
modifier = Modifier.padding(start = 16.dp, top = 16.dp, bottom = 4.dp)
|
||||||
)
|
)
|
||||||
LazyRow(modifier = Modifier.padding(horizontal = 8.dp)) {
|
LazyRow(modifier = Modifier.padding(horizontal = 8.dp)) {
|
||||||
@@ -107,16 +108,16 @@ fun SettingsAppearance(navController: BackStack<Route>) {
|
|||||||
item {
|
item {
|
||||||
ColorPreference(
|
ColorPreference(
|
||||||
preference = activeColors.primaryStateFlow,
|
preference = activeColors.primaryStateFlow,
|
||||||
title = "Color primary",
|
title = stringResource("color_primary"),
|
||||||
subtitle = "Displayed most frequently across your app",
|
subtitle = stringResource("color_primary_sub"),
|
||||||
unsetColor = MaterialTheme.colors.primary
|
unsetColor = MaterialTheme.colors.primary
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
ColorPreference(
|
ColorPreference(
|
||||||
preference = activeColors.secondaryStateFlow,
|
preference = activeColors.secondaryStateFlow,
|
||||||
title = "Color secondary",
|
title = stringResource("color_secondary"),
|
||||||
subtitle = "Accents select parts of the UI",
|
subtitle = stringResource("color_secondary_sub"),
|
||||||
unsetColor = MaterialTheme.colors.secondary
|
unsetColor = MaterialTheme.colors.secondary
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -152,7 +153,7 @@ private fun ThemeItem(
|
|||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(6.dp)
|
.padding(6.dp)
|
||||||
) {
|
) {
|
||||||
Text("Text", fontSize = 11.sp)
|
Text(stringResource("theme_text"), fontSize = 11.sp)
|
||||||
Button(
|
Button(
|
||||||
onClick = {},
|
onClick = {},
|
||||||
enabled = false,
|
enabled = false,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import androidx.compose.ui.unit.min
|
|||||||
import ca.gosyer.data.server.interactions.BackupInteractionHandler
|
import ca.gosyer.data.server.interactions.BackupInteractionHandler
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.prefs.PreferenceRow
|
import ca.gosyer.ui.base.prefs.PreferenceRow
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.ViewModel
|
import ca.gosyer.ui.base.vm.ViewModel
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
@@ -134,12 +135,12 @@ fun SettingsBackupScreen(navController: BackStack<Route>) {
|
|||||||
val creatingProgress by vm.creatingProgress.collectAsState()
|
val creatingProgress by vm.creatingProgress.collectAsState()
|
||||||
val creatingStatus by vm.creatingStatus.collectAsState()
|
val creatingStatus by vm.creatingStatus.collectAsState()
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Backup Settings", navController, true)
|
Toolbar(stringResource("settings_backup_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
PreferenceFile(
|
PreferenceFile(
|
||||||
"Restore Backup",
|
stringResource("backup_restore"),
|
||||||
"Restore a backup into Tachidesk",
|
stringResource("backup_restore_sub"),
|
||||||
restoring,
|
restoring,
|
||||||
restoringProgress,
|
restoringProgress,
|
||||||
restoreStatus
|
restoreStatus
|
||||||
@@ -149,8 +150,8 @@ fun SettingsBackupScreen(navController: BackStack<Route>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PreferenceFile(
|
PreferenceFile(
|
||||||
"Create Backup",
|
stringResource("backup_create"),
|
||||||
"Create a backup from Tachidesk",
|
stringResource("backup_create_sub"),
|
||||||
creating,
|
creating,
|
||||||
creatingProgress,
|
creatingProgress,
|
||||||
creatingStatus
|
creatingStatus
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsBrowseScreen(navController: BackStack<Route>) {
|
fun SettingsBrowseScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Browse Settings", navController, true)
|
Toolbar(stringResource("settings_browse_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsDownloadsScreen(navController: BackStack<Route>) {
|
fun SettingsDownloadsScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Download Settings", navController, true)
|
Toolbar(stringResource("settings_download_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.Divider
|
import androidx.compose.material.Divider
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
import ca.gosyer.data.ui.UiPreferences
|
import ca.gosyer.data.ui.UiPreferences
|
||||||
import ca.gosyer.data.ui.model.StartScreen
|
import ca.gosyer.data.ui.model.StartScreen
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.prefs.ChoicePreference
|
import ca.gosyer.ui.base.prefs.ChoicePreference
|
||||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.ViewModel
|
import ca.gosyer.ui.base.vm.ViewModel
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
@@ -28,7 +30,8 @@ import java.util.Locale
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SettingsGeneralViewModel @Inject constructor(
|
class SettingsGeneralViewModel @Inject constructor(
|
||||||
uiPreferences: UiPreferences
|
private val resources: XmlResourceBundle,
|
||||||
|
uiPreferences: UiPreferences,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val startScreen = uiPreferences.startScreen().asStateFlow()
|
val startScreen = uiPreferences.startScreen().asStateFlow()
|
||||||
@@ -37,22 +40,26 @@ class SettingsGeneralViewModel @Inject constructor(
|
|||||||
val dateFormat = uiPreferences.dateFormat().asStateFlow()
|
val dateFormat = uiPreferences.dateFormat().asStateFlow()
|
||||||
|
|
||||||
private val now: Instant = Instant.now()
|
private val now: Instant = Instant.now()
|
||||||
|
private val currentLocale = Locale.getDefault()
|
||||||
|
|
||||||
|
fun getLocalePair(locale: String): Pair<String, String> {
|
||||||
|
return locale to Locale.forLanguageTag(locale).getDisplayName(currentLocale)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getLanguageChoices(): Map<String, String> {
|
fun getLanguageChoices(): Map<String, String> {
|
||||||
val currentLocaleDisplayName =
|
val currentLocaleDisplayName = currentLocale.getDisplayName(currentLocale).capitalize(currentLocale)
|
||||||
Locale.getDefault().let { locale ->
|
|
||||||
locale.getDisplayName(locale).capitalize()
|
|
||||||
}
|
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"" to "System Default ($currentLocaleDisplayName)"
|
"" to resources.getString("language_system_default", currentLocaleDisplayName),
|
||||||
|
getLocalePair("en-CA")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getDateChoices(): Map<String, String> {
|
fun getDateChoices(): Map<String, String> {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"" to "System Default",
|
"" to resources.getStringA("date_system_default"),
|
||||||
"MM/dd/yy" to "MM/dd/yy",
|
"MM/dd/yy" to "MM/dd/yy",
|
||||||
"dd/MM/yy" to "dd/MM/yy",
|
"dd/MM/yy" to "dd/MM/yy",
|
||||||
"yyyy-MM-dd" to "yyyy-MM-dd"
|
"yyyy-MM-dd" to "yyyy-MM-dd"
|
||||||
@@ -73,21 +80,21 @@ class SettingsGeneralViewModel @Inject constructor(
|
|||||||
fun SettingsGeneralScreen(navController: BackStack<Route>) {
|
fun SettingsGeneralScreen(navController: BackStack<Route>) {
|
||||||
val vm = viewModel<SettingsGeneralViewModel>()
|
val vm = viewModel<SettingsGeneralViewModel>()
|
||||||
Column {
|
Column {
|
||||||
Toolbar("General Settings", navController, true)
|
Toolbar(stringResource("settings_general_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
preference = vm.startScreen,
|
preference = vm.startScreen,
|
||||||
title = "Start Screen",
|
title = stringResource("start_screen"),
|
||||||
choices = mapOf(
|
choices = mapOf(
|
||||||
StartScreen.Library to "Library",
|
StartScreen.Library to stringResource("location_library"),
|
||||||
StartScreen.Sources to "Sources",
|
StartScreen.Sources to stringResource("location_sources"),
|
||||||
StartScreen.Extensions to "Extensions",
|
StartScreen.Extensions to stringResource("location_extensions"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
SwitchPreference(preference = vm.confirmExit, title = "Confirm Exit")
|
SwitchPreference(preference = vm.confirmExit, title = stringResource("confirm_exit"))
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Divider()
|
Divider()
|
||||||
@@ -95,14 +102,14 @@ fun SettingsGeneralScreen(navController: BackStack<Route>) {
|
|||||||
item {
|
item {
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
preference = vm.language,
|
preference = vm.language,
|
||||||
title = "Language",
|
title = stringResource("language"),
|
||||||
choices = vm.getLanguageChoices(),
|
choices = vm.getLanguageChoices(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
preference = vm.dateFormat,
|
preference = vm.dateFormat,
|
||||||
title = "Date Format",
|
title = stringResource("date_format"),
|
||||||
choices = vm.getDateChoices()
|
choices = vm.getDateChoices()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import ca.gosyer.data.server.interactions.CategoryInteractionHandler
|
|||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.prefs.PreferenceRow
|
import ca.gosyer.ui.base.prefs.PreferenceRow
|
||||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.ViewModel
|
import ca.gosyer.ui.base.vm.ViewModel
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.categories.openCategoriesMenu
|
import ca.gosyer.ui.categories.openCategoriesMenu
|
||||||
@@ -50,14 +51,14 @@ fun SettingsLibraryScreen(navController: BackStack<Route>) {
|
|||||||
val vm = viewModel<SettingsLibraryViewModel>()
|
val vm = viewModel<SettingsLibraryViewModel>()
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Library Settings", navController, true)
|
Toolbar(stringResource("settings_library_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
SwitchPreference(preference = vm.showAllCategory, title = "Show all category")
|
SwitchPreference(preference = vm.showAllCategory, title = stringResource("show_all_category"))
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
"Categories",
|
stringResource("location_categories"),
|
||||||
onClick = { openCategoriesMenu(vm::refreshCategoryCount) },
|
onClick = { openCategoriesMenu(vm::refreshCategoryCount) },
|
||||||
subtitle = vm.categories.collectAsState().value.toString()
|
subtitle = vm.categories.collectAsState().value.toString()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsParentalControlsScreen(navController: BackStack<Route>) {
|
fun SettingsParentalControlsScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Parental Control Settings", navController, true)
|
Toolbar(stringResource("settings_parental_control_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ import ca.gosyer.data.reader.ReaderPreferences
|
|||||||
import ca.gosyer.data.reader.model.Direction
|
import ca.gosyer.data.reader.model.Direction
|
||||||
import ca.gosyer.data.reader.model.ImageScale
|
import ca.gosyer.data.reader.model.ImageScale
|
||||||
import ca.gosyer.data.reader.model.NavigationMode
|
import ca.gosyer.data.reader.model.NavigationMode
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.prefs.ChoicePreference
|
import ca.gosyer.ui.base.prefs.ChoicePreference
|
||||||
import ca.gosyer.ui.base.prefs.ExpandablePreference
|
import ca.gosyer.ui.base.prefs.ExpandablePreference
|
||||||
import ca.gosyer.ui.base.prefs.PreferenceMutableStateFlow
|
import ca.gosyer.ui.base.prefs.PreferenceMutableStateFlow
|
||||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||||
import ca.gosyer.ui.base.prefs.asStateIn
|
import ca.gosyer.ui.base.prefs.asStateIn
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.ViewModel
|
import ca.gosyer.ui.base.vm.ViewModel
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
@@ -36,6 +38,7 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class SettingsReaderViewModel @Inject constructor(
|
class SettingsReaderViewModel @Inject constructor(
|
||||||
|
private val resources: XmlResourceBundle,
|
||||||
readerPreferences: ReaderPreferences
|
readerPreferences: ReaderPreferences
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
val modes = readerPreferences.modes().asStateFlow()
|
val modes = readerPreferences.modes().asStateFlow()
|
||||||
@@ -56,10 +59,10 @@ class SettingsReaderViewModel @Inject constructor(
|
|||||||
}.launchIn(scope)
|
}.launchIn(scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDirectionChoices() = Direction.values().associate { it to it.res }
|
fun getDirectionChoices() = Direction.values().associate { it to resources.getStringA(it.res) }
|
||||||
|
|
||||||
fun getPaddingChoices() = mapOf(
|
fun getPaddingChoices() = mapOf(
|
||||||
0 to "None",
|
0 to resources.getStringA("page_padding_none"),
|
||||||
8 to "8 Dp",
|
8 to "8 Dp",
|
||||||
16 to "16 Dp",
|
16 to "16 Dp",
|
||||||
32 to "32 Dp"
|
32 to "32 Dp"
|
||||||
@@ -67,23 +70,23 @@ class SettingsReaderViewModel @Inject constructor(
|
|||||||
|
|
||||||
fun getMaxSizeChoices(direction: Direction) = if (direction == Direction.Right || direction == Direction.Left) {
|
fun getMaxSizeChoices(direction: Direction) = if (direction == Direction.Right || direction == Direction.Left) {
|
||||||
mapOf(
|
mapOf(
|
||||||
0 to "Unrestricted",
|
0 to resources.getStringA("max_size_unrestricted"),
|
||||||
700 to "700 Dp",
|
700 to "700 Dp",
|
||||||
900 to "900 Dp",
|
900 to "900 Dp",
|
||||||
1100 to "1100 Dp"
|
1100 to "1100 Dp"
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
mapOf(
|
mapOf(
|
||||||
0 to "Unrestricted",
|
0 to resources.getStringA("max_size_unrestricted"),
|
||||||
500 to "500 Dp",
|
500 to "500 Dp",
|
||||||
700 to "700 Dp",
|
700 to "700 Dp",
|
||||||
900 to "900 Dp"
|
900 to "900 Dp"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getImageScaleChoices() = ImageScale.values().associate { it to it.res }
|
fun getImageScaleChoices() = ImageScale.values().associate { it to resources.getStringA(it.res) }
|
||||||
|
|
||||||
fun getNavigationModeChoices() = NavigationMode.values().associate { it to it.res }
|
fun getNavigationModeChoices() = NavigationMode.values().associate { it to resources.getStringA(it.res) }
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ReaderModePreference(
|
data class ReaderModePreference(
|
||||||
@@ -118,13 +121,13 @@ fun SettingsReaderScreen(navController: BackStack<Route>) {
|
|||||||
val vm = viewModel<SettingsReaderViewModel>()
|
val vm = viewModel<SettingsReaderViewModel>()
|
||||||
val modeSettings by vm.modeSettings.collectAsState()
|
val modeSettings by vm.modeSettings.collectAsState()
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Reader Settings", navController, true)
|
Toolbar(stringResource("settings_reader"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
vm.selectedMode,
|
vm.selectedMode,
|
||||||
vm.modes.collectAsState().value.associateWith { it },
|
vm.modes.collectAsState().value.associateWith { it },
|
||||||
"Reader Mode"
|
stringResource("reader_mode")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
@@ -136,13 +139,13 @@ fun SettingsReaderScreen(navController: BackStack<Route>) {
|
|||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
it.direction,
|
it.direction,
|
||||||
vm.getDirectionChoices(),
|
vm.getDirectionChoices(),
|
||||||
"Direction",
|
stringResource("direction"),
|
||||||
enabled = !it.defaultMode
|
enabled = !it.defaultMode
|
||||||
)
|
)
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
it.continuous,
|
it.continuous,
|
||||||
"Continuous",
|
stringResource("continuous"),
|
||||||
"If the reader is a pager or a scrolling window",
|
stringResource("continuous_sub"),
|
||||||
enabled = !it.defaultMode
|
enabled = !it.defaultMode
|
||||||
)
|
)
|
||||||
val continuous by it.continuous.collectAsState()
|
val continuous by it.continuous.collectAsState()
|
||||||
@@ -150,13 +153,13 @@ fun SettingsReaderScreen(navController: BackStack<Route>) {
|
|||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
it.padding,
|
it.padding,
|
||||||
vm.getPaddingChoices(),
|
vm.getPaddingChoices(),
|
||||||
"Page Padding"
|
stringResource("page_padding")
|
||||||
)
|
)
|
||||||
val direction by it.direction.collectAsState()
|
val direction by it.direction.collectAsState()
|
||||||
val (title, subtitle) = if (direction == Direction.Up || direction == Direction.Down) {
|
val (title, subtitle) = if (direction == Direction.Up || direction == Direction.Down) {
|
||||||
"Force fit width" to "When the window's width is over the images width, scale the image to the window"
|
stringResource("force_fit_width") to stringResource("force_fit_width_sub")
|
||||||
} else {
|
} else {
|
||||||
"Force fit height" to "When the window's height is over the images height, scale the image to the window"
|
stringResource("force_fit_height") to stringResource("force_fit_height_sub")
|
||||||
}
|
}
|
||||||
SwitchPreference(
|
SwitchPreference(
|
||||||
it.fitSize,
|
it.fitSize,
|
||||||
@@ -165,9 +168,9 @@ fun SettingsReaderScreen(navController: BackStack<Route>) {
|
|||||||
)
|
)
|
||||||
val maxSize by it.maxSize.collectAsState()
|
val maxSize by it.maxSize.collectAsState()
|
||||||
val (maxSizeTitle, maxSizeSubtitle) = if (direction == Direction.Up || direction == Direction.Down) {
|
val (maxSizeTitle, maxSizeSubtitle) = if (direction == Direction.Up || direction == Direction.Down) {
|
||||||
"Max width" to "Width to restrict a image from going over, currently $maxSize" + "dp. Works with the above setting to scale images up but restrict them to a certain amount"
|
stringResource("max_width") to stringResource("max_width_sub", maxSize.toString())
|
||||||
} else {
|
} else {
|
||||||
"Max height" to "Height to restrict a image from going over, currently $maxSize" + "dp. Works with the above setting to scale images up but restrict them to a certain amount"
|
stringResource("max_height") to stringResource("max_height_sub", maxSize.toString())
|
||||||
}
|
}
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
it.maxSize,
|
it.maxSize,
|
||||||
@@ -179,13 +182,13 @@ fun SettingsReaderScreen(navController: BackStack<Route>) {
|
|||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
it.imageScale,
|
it.imageScale,
|
||||||
vm.getImageScaleChoices(),
|
vm.getImageScaleChoices(),
|
||||||
"Image Scale"
|
stringResource("image_scale")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ChoicePreference(
|
ChoicePreference(
|
||||||
it.navigationMode,
|
it.navigationMode,
|
||||||
vm.getNavigationModeChoices(),
|
vm.getNavigationModeChoices(),
|
||||||
"Navigation mode"
|
stringResource("navigation_mode")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,94 +20,95 @@ import androidx.compose.material.icons.filled.Tune
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.prefs.PreferenceRow
|
import ca.gosyer.ui.base.prefs.PreferenceRow
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(navController: BackStack<Route>) {
|
fun SettingsScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Settings", closable = false)
|
Toolbar(stringResource("location_settings"), closable = false)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "General",
|
title = stringResource("settings_general"),
|
||||||
icon = Icons.Default.Tune,
|
icon = Icons.Default.Tune,
|
||||||
onClick = { navController.push(Route.SettingsGeneral) }
|
onClick = { navController.push(Route.SettingsGeneral) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Appearance",
|
title = stringResource("settings_appearance"),
|
||||||
icon = Icons.Default.Palette,
|
icon = Icons.Default.Palette,
|
||||||
onClick = { navController.push(Route.SettingsAppearance) }
|
onClick = { navController.push(Route.SettingsAppearance) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Server",
|
title = stringResource("settings_server"),
|
||||||
icon = Icons.Default.Computer,
|
icon = Icons.Default.Computer,
|
||||||
onClick = { navController.push(Route.SettingsServer) }
|
onClick = { navController.push(Route.SettingsServer) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Library",
|
title = stringResource("settings_library"),
|
||||||
icon = Icons.Default.CollectionsBookmark,
|
icon = Icons.Default.CollectionsBookmark,
|
||||||
onClick = { navController.push(Route.SettingsLibrary) }
|
onClick = { navController.push(Route.SettingsLibrary) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Reader",
|
title = stringResource("settings_reader"),
|
||||||
icon = Icons.Default.ChromeReaderMode,
|
icon = Icons.Default.ChromeReaderMode,
|
||||||
onClick = { navController.push(Route.SettingsReader) }
|
onClick = { navController.push(Route.SettingsReader) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/*item {
|
/*item {
|
||||||
Pref(
|
Pref(
|
||||||
title = "Downloads",
|
title = stringResource("settings_download"),
|
||||||
icon = Icons.Default.GetApp,
|
icon = Icons.Default.GetApp,
|
||||||
onClick = { navController.push(Route.SettingsDownloads) }
|
onClick = { navController.push(Route.SettingsDownloads) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Pref(
|
Pref(
|
||||||
title = "Tracking",
|
title = stringResource("settings_tracking"),
|
||||||
icon = Icons.Default.Sync,
|
icon = Icons.Default.Sync,
|
||||||
onClick = { navController.push(Route.SettingsTracking) }
|
onClick = { navController.push(Route.SettingsTracking) }
|
||||||
)
|
)
|
||||||
}*/
|
}*/
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Browse",
|
title = stringResource("settings_browse"),
|
||||||
icon = Icons.Default.Explore,
|
icon = Icons.Default.Explore,
|
||||||
onClick = { navController.push(Route.SettingsBrowse) }
|
onClick = { navController.push(Route.SettingsBrowse) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Backup",
|
title = stringResource("settings_backup"),
|
||||||
icon = Icons.Default.Backup,
|
icon = Icons.Default.Backup,
|
||||||
onClick = { navController.push(Route.SettingsBackup) }
|
onClick = { navController.push(Route.SettingsBackup) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
/*item {
|
/*item {
|
||||||
Pref(
|
Pref(
|
||||||
title = "Security",
|
title = stringResource("settings_security"),
|
||||||
icon = Icons.Default.Security,
|
icon = Icons.Default.Security,
|
||||||
onClick = { navController.push(Route.SettingsSecurity) }
|
onClick = { navController.push(Route.SettingsSecurity) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
Pref(
|
Pref(
|
||||||
title = "Parental Controls",
|
title = stringResource("settings_parental_controls"),
|
||||||
icon = Icons.Default.PeopleOutline,
|
icon = Icons.Default.PeopleOutline,
|
||||||
onClick = { navController.push(Route.SettingsParentalControls) }
|
onClick = { navController.push(Route.SettingsParentalControls) }
|
||||||
)
|
)
|
||||||
}*/
|
}*/
|
||||||
item {
|
item {
|
||||||
PreferenceRow(
|
PreferenceRow(
|
||||||
title = "Advanced",
|
title = stringResource("settings_advanced"),
|
||||||
icon = Icons.Default.Code,
|
icon = Icons.Default.Code,
|
||||||
onClick = { navController.push(Route.SettingsAdvanced) }
|
onClick = { navController.push(Route.SettingsAdvanced) }
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsSecurityScreen(navController: BackStack<Route>) {
|
fun SettingsSecurityScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Security Settings", navController, true)
|
Toolbar(stringResource("settings_security_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import ca.gosyer.ui.base.prefs.EditTextPreference
|
|||||||
import ca.gosyer.ui.base.prefs.SwitchPreference
|
import ca.gosyer.ui.base.prefs.SwitchPreference
|
||||||
import ca.gosyer.ui.base.prefs.asStateIn
|
import ca.gosyer.ui.base.prefs.asStateIn
|
||||||
import ca.gosyer.ui.base.prefs.asStringStateIn
|
import ca.gosyer.ui.base.prefs.asStringStateIn
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.ViewModel
|
import ca.gosyer.ui.base.vm.ViewModel
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
@@ -34,14 +35,14 @@ class SettingsServerViewModel @Inject constructor(
|
|||||||
fun SettingsServerScreen(navController: BackStack<Route>) {
|
fun SettingsServerScreen(navController: BackStack<Route>) {
|
||||||
val vm = viewModel<SettingsServerViewModel>()
|
val vm = viewModel<SettingsServerViewModel>()
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Server Settings", navController, true)
|
Toolbar(stringResource("settings_server_screen"), navController, true)
|
||||||
SwitchPreference(preference = vm.host, title = "Host server inside TachideskJUI")
|
SwitchPreference(preference = vm.host, title = stringResource("host_server"))
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
item {
|
item {
|
||||||
EditTextPreference(vm.server, "Server Url", subtitle = vm.server.collectAsState().value)
|
EditTextPreference(vm.server, stringResource("server_url"), subtitle = vm.server.collectAsState().value)
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
EditTextPreference(vm.port, "Server Port", subtitle = vm.port.collectAsState().value)
|
EditTextPreference(vm.port, stringResource("server_port"), subtitle = vm.port.collectAsState().value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.main.Route
|
import ca.gosyer.ui.main.Route
|
||||||
import com.github.zsoltk.compose.router.BackStack
|
import com.github.zsoltk.compose.router.BackStack
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsTrackingScreen(navController: BackStack<Route>) {
|
fun SettingsTrackingScreen(navController: BackStack<Route>) {
|
||||||
Column {
|
Column {
|
||||||
Toolbar("Tracking Settings", navController, true)
|
Toolbar(stringResource("settings_tracking_screen"), navController, true)
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import ca.gosyer.data.models.Source
|
|||||||
import ca.gosyer.ui.base.components.KtorImage
|
import ca.gosyer.ui.base.components.KtorImage
|
||||||
import ca.gosyer.ui.base.components.Toolbar
|
import ca.gosyer.ui.base.components.Toolbar
|
||||||
import ca.gosyer.ui.base.components.combinedMouseClickable
|
import ca.gosyer.ui.base.components.combinedMouseClickable
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.ui.manga.openMangaMenu
|
import ca.gosyer.ui.manga.openMangaMenu
|
||||||
import ca.gosyer.ui.sources.components.SourceHomeScreen
|
import ca.gosyer.ui.sources.components.SourceHomeScreen
|
||||||
@@ -75,7 +76,7 @@ fun SourcesMenu(bundle: Bundle, onMangaClick: (Long) -> Unit) {
|
|||||||
Surface {
|
Surface {
|
||||||
Column {
|
Column {
|
||||||
Toolbar(
|
Toolbar(
|
||||||
selectedSourceTab?.name ?: "Sources",
|
selectedSourceTab?.name ?: stringResource("location_sources"),
|
||||||
closable = selectedSourceTab != null,
|
closable = selectedSourceTab != null,
|
||||||
onClose = {
|
onClose = {
|
||||||
selectedSourceTab?.let { vm.closeTab(it) }
|
selectedSourceTab?.let { vm.closeTab(it) }
|
||||||
@@ -110,14 +111,14 @@ fun SourcesMenu(bundle: Bundle, onMangaClick: (Long) -> Unit) {
|
|||||||
shape = RoundedCornerShape(4.dp),
|
shape = RoundedCornerShape(4.dp),
|
||||||
elevation = 4.dp
|
elevation = 4.dp
|
||||||
) {
|
) {
|
||||||
Text(source?.name ?: "Home", modifier = Modifier.padding(10.dp))
|
Text(source?.name ?: stringResource("sources_home"), modifier = Modifier.padding(10.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if (source != null) {
|
if (source != null) {
|
||||||
KtorImage(source.iconUrl(serverUrl), imageModifier = modifier)
|
KtorImage(source.iconUrl(serverUrl), imageModifier = modifier)
|
||||||
} else {
|
} else {
|
||||||
Icon(Icons.Default.Home, "Home", modifier = modifier)
|
Icon(Icons.Default.Home, stringResource("sources_home"), modifier = modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import ca.gosyer.data.models.Manga
|
|||||||
import ca.gosyer.data.models.Source
|
import ca.gosyer.data.models.Source
|
||||||
import ca.gosyer.ui.base.components.LoadingScreen
|
import ca.gosyer.ui.base.components.LoadingScreen
|
||||||
import ca.gosyer.ui.base.components.MangaGridItem
|
import ca.gosyer.ui.base.components.MangaGridItem
|
||||||
|
import ca.gosyer.ui.base.resources.stringResource
|
||||||
import ca.gosyer.ui.base.vm.viewModel
|
import ca.gosyer.ui.base.vm.viewModel
|
||||||
import ca.gosyer.util.compose.persistentLazyListState
|
import ca.gosyer.util.compose.persistentLazyListState
|
||||||
import com.github.zsoltk.compose.savedinstancestate.Bundle
|
import com.github.zsoltk.compose.savedinstancestate.Bundle
|
||||||
@@ -97,7 +98,7 @@ private fun MangaTable(
|
|||||||
enabled = !isLoading,
|
enabled = !isLoading,
|
||||||
modifier = Modifier.align(Alignment.TopEnd)
|
modifier = Modifier.align(Alignment.TopEnd)
|
||||||
) {
|
) {
|
||||||
Text(text = if (isLatest) "To Browse" else "To Latest")
|
Text(text = stringResource(if (isLatest) "move_to_browse" else "move_to_latest"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,13 @@ package ca.gosyer.util.compose
|
|||||||
import androidx.compose.desktop.Window
|
import androidx.compose.desktop.Window
|
||||||
import androidx.compose.desktop.WindowEvents
|
import androidx.compose.desktop.WindowEvents
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import androidx.compose.ui.window.v1.MenuBar
|
import androidx.compose.ui.window.v1.MenuBar
|
||||||
|
import ca.gosyer.common.di.AppScope
|
||||||
|
import ca.gosyer.data.translation.XmlResourceBundle
|
||||||
|
import ca.gosyer.ui.base.resources.LocalResources
|
||||||
import ca.gosyer.ui.base.theme.AppTheme
|
import ca.gosyer.ui.base.theme.AppTheme
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
|
|
||||||
@@ -28,9 +32,14 @@ fun ThemedWindow(
|
|||||||
onDismissRequest: (() -> Unit)? = null,
|
onDismissRequest: (() -> Unit)? = null,
|
||||||
content: @Composable () -> Unit = { }
|
content: @Composable () -> Unit = { }
|
||||||
) {
|
) {
|
||||||
|
val resources = AppScope.getInstance<XmlResourceBundle>()
|
||||||
Window(title, size, location, centered, icon, menuBar, undecorated, resizable, events, onDismissRequest) {
|
Window(title, size, location, centered, icon, menuBar, undecorated, resizable, events, onDismissRequest) {
|
||||||
AppTheme {
|
CompositionLocalProvider(
|
||||||
content()
|
LocalResources provides resources
|
||||||
|
) {
|
||||||
|
AppTheme {
|
||||||
|
content()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/main/resources/values/values-en-CA/strings.xml
Normal file
12
src/main/resources/values/values-en-CA/strings.xml
Normal file
@@ -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/.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="color_primary">Colour primary</string>
|
||||||
|
<string name="color_secondary">Colour secondary</string>
|
||||||
|
<string name="action_favorite">Favourite</string>
|
||||||
|
<string name="action_remove_favorite">UnFavourite</string>
|
||||||
|
</resources>
|
||||||
167
src/main/resources/values/values/strings.xml
Normal file
167
src/main/resources/values/values/strings.xml
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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/.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">TachideskJUI</string>
|
||||||
|
|
||||||
|
<!-- Main Menu -->
|
||||||
|
<string name="tachidesk_doesnt_exist">Tachidesk jar does not exist, run Tachidesk yourself</string>
|
||||||
|
<string name="unable_to_start_server">Unable to start server</string>
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_yes">Yes</string>
|
||||||
|
<string name="action_no">No</string>
|
||||||
|
<string name="action_cancel">Cancel</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="action_start_anyway">Start anyway</string>
|
||||||
|
<string name="action_rename">Rename</string>
|
||||||
|
<string name="action_create">Create</string>
|
||||||
|
<string name="action_add">Add</string>
|
||||||
|
<string name="action_pause">Pause</string>
|
||||||
|
<string name="action_continue">Continue</string>
|
||||||
|
<string name="action_clear_queue">Clear queue</string>
|
||||||
|
<string name="action_move_to_bottom">Move to bottom</string>
|
||||||
|
<string name="action_install">Install</string>
|
||||||
|
<string name="action_uninstall">Uninstall</string>
|
||||||
|
<string name="action_update">Update</string>
|
||||||
|
<string name="action_toggle_read">Toggle read</string>
|
||||||
|
<string name="action_mark_previous_read">Mark previous as read</string>
|
||||||
|
<string name="action_toggle_bookmarked">Toggle bookmarked</string>
|
||||||
|
<string name="action_favorite">Favorite</string>
|
||||||
|
<string name="action_remove_favorite">UnFavorite</string>
|
||||||
|
<string name="action_refresh_manga">Refresh manga</string>
|
||||||
|
|
||||||
|
<!-- Locations -->
|
||||||
|
<string name="location_library">Library</string>
|
||||||
|
<string name="location_sources">Sources</string>
|
||||||
|
<string name="location_extensions">Extensions</string>
|
||||||
|
<string name="location_downloads">Downloads</string>
|
||||||
|
<string name="location_settings">Settings</string>
|
||||||
|
<string name="location_categories">Categories</string>
|
||||||
|
<string name="location_manga">Manga</string>
|
||||||
|
|
||||||
|
<!-- Categories Menu -->
|
||||||
|
<string name="categories_delete_confirm">Do you wish to delete the category %1$s?</string>
|
||||||
|
|
||||||
|
<!-- Downloads Menu -->
|
||||||
|
<string name="downloads_remaining">%1$s remaining</string>
|
||||||
|
|
||||||
|
<!-- Extensions Menu -->
|
||||||
|
<string name="enabled_languages">Enabled languages</string>
|
||||||
|
|
||||||
|
<!-- Library Menu -->
|
||||||
|
<string name="default_category">Default</string>
|
||||||
|
|
||||||
|
<!-- Manga Menu -->
|
||||||
|
<string name="page_progress">Page %1$s</string>
|
||||||
|
|
||||||
|
<!-- Sources Menu -->
|
||||||
|
<string name="sources_home">Home</string>
|
||||||
|
<string name="move_to_browse">To Browse</string>
|
||||||
|
<string name="move_to_latest">To Latest</string>
|
||||||
|
|
||||||
|
<!-- Reader Menu -->
|
||||||
|
<string name="no_pages_found">No pages found</string>
|
||||||
|
<string name="no_previous_chapter">There is no previous chapter</string>
|
||||||
|
<string name="previous_chapter">Previous:\n %1$s</string>
|
||||||
|
<string name="next_chapter">Next:\n %1$s</string>
|
||||||
|
<string name="no_next_chapter">There is no next chapter</string>
|
||||||
|
|
||||||
|
<!-- Settings-->
|
||||||
|
<string name="settings_advanced">Advanced</string>
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_backup">Backup</string>
|
||||||
|
<string name="settings_browse">Browse</string>
|
||||||
|
<string name="settings_download">Download</string>
|
||||||
|
<string name="settings_general">General</string>
|
||||||
|
<string name="settings_library">Library</string>
|
||||||
|
<string name="settings_parental_controls">Parental Controls</string>
|
||||||
|
<string name="settings_reader">Reader</string>
|
||||||
|
<string name="settings_security">Security</string>
|
||||||
|
<string name="settings_server">Server</string>
|
||||||
|
<string name="settings_tracking">Tracking</string>
|
||||||
|
|
||||||
|
<!-- Settings Menu Titles-->
|
||||||
|
<string name="settings_advanced_screen">Advanced Settings</string>
|
||||||
|
<string name="settings_appearance_screen">Appearance Settings</string>
|
||||||
|
<string name="settings_backup_screen">Backup Settings</string>
|
||||||
|
<string name="settings_browse_screen">Browse Settings</string>
|
||||||
|
<string name="settings_download_screen">Download Settings</string>
|
||||||
|
<string name="settings_general_screen">General Settings</string>
|
||||||
|
<string name="settings_library_screen">Library Settings</string>
|
||||||
|
<string name="settings_parental_control_screen">Parental Control Settings</string>
|
||||||
|
<string name="settings_reader_screen">Reader Settings</string>
|
||||||
|
<string name="settings_security_screen">Security Settings</string>
|
||||||
|
<string name="settings_server_screen">Server Settings</string>
|
||||||
|
<string name="settings_tracking_screen">Tracking Settings</string>
|
||||||
|
|
||||||
|
<!-- Appearance Settings -->
|
||||||
|
<string name="theme">Theme</string>
|
||||||
|
<string name="theme_light">Light</string>
|
||||||
|
<string name="theme_Dark">Light</string>
|
||||||
|
<string name="theme_text">Text</string>
|
||||||
|
<string name="preset_themes">Preset themes</string>
|
||||||
|
<string name="color_primary">Color primary</string>
|
||||||
|
<string name="color_primary_sub">Displayed most frequently across your app</string>
|
||||||
|
<string name="color_secondary">Color secondary</string>
|
||||||
|
<string name="color_secondary_sub">Accents select parts of the UI</string>
|
||||||
|
|
||||||
|
<!-- Backup Settings -->
|
||||||
|
<string name="backup_restore">Restore Backup</string>
|
||||||
|
<string name="backup_restore_sub">Restore a backup into Tachidesk</string>
|
||||||
|
<string name="backup_create">Create Backup</string>
|
||||||
|
<string name="backup_create_sub">Create a backup from Tachidesk</string>
|
||||||
|
|
||||||
|
<!-- General Settings -->
|
||||||
|
<string name="start_screen">Start Screen</string>
|
||||||
|
<string name="confirm_exit">Confirm Exit</string>
|
||||||
|
<string name="language">Language</string>
|
||||||
|
<string name="language_system_default">System Default (%1$s)</string>
|
||||||
|
<string name="date_format">Date Format</string>
|
||||||
|
<string name="date_system_default">System Default</string>
|
||||||
|
|
||||||
|
<!-- Library Settings -->
|
||||||
|
<string name="show_all_category">Show all category</string>
|
||||||
|
|
||||||
|
<!-- Reader Settings -->
|
||||||
|
<string name="reader_mode">Reader Mode</string>
|
||||||
|
<string name="direction">Direction</string>
|
||||||
|
<string name="dir_down">Down</string>
|
||||||
|
<string name="dir_rtl">RTL</string>
|
||||||
|
<string name="dir_ltr">LTR</string>
|
||||||
|
<string name="dir_up">Up</string>
|
||||||
|
<string name="continuous">Continuous</string>
|
||||||
|
<string name="continuous_sub">If the reader is a pager or a scrolling window</string>
|
||||||
|
<string name="page_padding">Page Padding</string>
|
||||||
|
<string name="page_padding_none">None</string>
|
||||||
|
<string name="force_fit_width">Force fit width</string>
|
||||||
|
<string name="force_fit_width_sub">When the window's width is over the images width, scale the image to the window</string>
|
||||||
|
<string name="force_fit_height">Force fit height</string>
|
||||||
|
<string name="force_fit_height_sub">When the window's height is over the images height, scale the image to the window</string>
|
||||||
|
<string name="max_width">Max width</string>
|
||||||
|
<string name="max_width_sub">Width to restrict a image from going over, currently %1$sdp. Works with the above setting to scale images up but restrict them to a certain amount</string>
|
||||||
|
<string name="max_height">Max height</string>
|
||||||
|
<string name="max_height_sub">Height to restrict a image from going over, currently %1$sdp. Works with the above setting to scale images up but restrict them to a certain amount</string>
|
||||||
|
<string name="max_size_unrestricted">Unrestricted</string>
|
||||||
|
<string name="image_scale">Image Scale</string>
|
||||||
|
<string name="scale_fit_screen">Fit Screen</string>
|
||||||
|
<string name="scale_stretch">Stretch</string>
|
||||||
|
<string name="scale_fit_width">Fit Width</string>
|
||||||
|
<string name="scale_fit_height">Fit Height</string>
|
||||||
|
<string name="scale_original">Original Size</string>
|
||||||
|
<string name="scale_smart">Smart Fit</string>
|
||||||
|
<string name="navigation_mode">Navigation mode</string>
|
||||||
|
<string name="nav_l_shaped">L shaped</string>
|
||||||
|
<string name="nav_kindle_ish">Kindle-ish</string>
|
||||||
|
<string name="nav_edge">Edge</string>
|
||||||
|
<string name="nav_left_right">Right and Left</string>
|
||||||
|
|
||||||
|
<!-- Server Settings -->
|
||||||
|
<string name="host_server">Host server inside TachideskJUI</string>
|
||||||
|
<string name="server_url">Server Url</string>
|
||||||
|
<string name="server_port">Server Port</string>
|
||||||
|
</resources>
|
||||||
Reference in New Issue
Block a user