Migrate to multiplatform string resources (#10147)

* Migrate to multiplatform string resources

* Move plurals translations into separate files

* Fix lint check on generated files

(cherry picked from commit 46e734fc8eefb8c06a880194e702559ca3fa769d)

# Conflicts:
#	app/src/main/java/eu/kanade/presentation/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt
#	app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt
#	app/src/main/java/eu/kanade/presentation/browse/SourcesScreen.kt
#	app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceDialogs.kt
#	app/src/main/java/eu/kanade/presentation/browse/components/BrowseSourceToolbar.kt
#	app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt
#	app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt
#	app/src/main/java/eu/kanade/presentation/manga/components/MangaBottomActionMenu.kt
#	app/src/main/java/eu/kanade/presentation/manga/components/MangaDialogs.kt
#	app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsLibraryScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsMainScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsReaderScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSecurityScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/about/AboutScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/advanced/ClearDatabaseScreen.kt
#	app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt
#	app/src/main/java/eu/kanade/presentation/reader/ReaderPageActionsDialog.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/BottomReaderBar.kt
#	app/src/main/java/eu/kanade/presentation/reader/appbars/ReaderAppBars.kt
#	app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt
#	app/src/main/java/eu/kanade/presentation/reader/settings/GeneralSettingsPage.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/download/Downloader.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt
#	app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateNotifier.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/BrowseTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/MigrationFlags.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/manga/MigrateMangaScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrateSourceTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/history/HistoryTab.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreen.kt
#	app/src/main/java/eu/kanade/tachiyomi/ui/updates/UpdatesTab.kt
#	build.gradle.kts
#	i18n/build.gradle.kts
#	i18n/src/commonMain/resources/MR/base/strings_sy.xml
#	i18n/src/commonMain/resources/MR/fr/strings_sy.xml
#	i18n/src/commonMain/resources/MR/in/strings_sy.xml
#	i18n/src/commonMain/resources/MR/pt-rBR/strings_sy.xml
#	i18n/src/commonMain/resources/MR/ru/strings_sy.xml
#	i18n/src/commonMain/resources/MR/zh-rCN/strings_sy.xml
#	i18n/src/commonMain/resources/MR/zh-rTW/strings_sy.xml
This commit is contained in:
arkon 2023-11-18 13:54:56 -05:00 committed by Jobobby04
parent 120ac6dbda
commit 1eccf9fad8
318 changed files with 5701 additions and 6080 deletions

View File

@ -140,6 +140,9 @@ android {
dependencies {
implementation(project(":i18n"))
// SY -->
implementation(project(":i18n-sy"))
// SY <--
implementation(project(":core"))
implementation(project(":core-metadata"))
implementation(project(":source-api"))

View File

@ -1,12 +1,12 @@
package eu.kanade.domain.base
import android.content.Context
import androidx.annotation.StringRes
import eu.kanade.tachiyomi.R
import dev.icerock.moko.resources.StringResource
import eu.kanade.tachiyomi.util.system.isPreviewBuildType
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.i18n.MR
class BasePreferences(
val context: Context,
@ -24,10 +24,10 @@ class BasePreferences(
fun acraEnabled() = preferenceStore.getBoolean("acra.enable", isPreviewBuildType || isReleaseBuildType)
enum class ExtensionInstaller(@StringRes val titleResId: Int) {
LEGACY(R.string.ext_installer_legacy),
PACKAGEINSTALLER(R.string.ext_installer_packageinstaller),
SHIZUKU(R.string.ext_installer_shizuku),
PRIVATE(R.string.ext_installer_private),
enum class ExtensionInstaller(val titleRes: StringResource) {
LEGACY(MR.strings.ext_installer_legacy),
PACKAGEINSTALLER(MR.strings.ext_installer_packageinstaller),
SHIZUKU(MR.strings.ext_installer_shizuku),
PRIVATE(MR.strings.ext_installer_private),
}
}

View File

@ -1,19 +1,20 @@
package eu.kanade.domain.ui.model
import eu.kanade.tachiyomi.R
import dev.icerock.moko.resources.StringResource
import tachiyomi.i18n.MR
enum class AppTheme(val titleResId: Int?) {
DEFAULT(R.string.label_default),
MONET(R.string.theme_monet),
GREEN_APPLE(R.string.theme_greenapple),
LAVENDER(R.string.theme_lavender),
MIDNIGHT_DUSK(R.string.theme_midnightdusk),
STRAWBERRY_DAIQUIRI(R.string.theme_strawberrydaiquiri),
TAKO(R.string.theme_tako),
TEALTURQUOISE(R.string.theme_tealturquoise),
TIDAL_WAVE(R.string.theme_tidalwave),
YINYANG(R.string.theme_yinyang),
YOTSUBA(R.string.theme_yotsuba),
enum class AppTheme(val titleRes: StringResource?) {
DEFAULT(MR.strings.label_default),
MONET(MR.strings.theme_monet),
GREEN_APPLE(MR.strings.theme_greenapple),
LAVENDER(MR.strings.theme_lavender),
MIDNIGHT_DUSK(MR.strings.theme_midnightdusk),
STRAWBERRY_DAIQUIRI(MR.strings.theme_strawberrydaiquiri),
TAKO(MR.strings.theme_tako),
TEALTURQUOISE(MR.strings.theme_tealturquoise),
TIDAL_WAVE(MR.strings.theme_tidalwave),
YINYANG(MR.strings.theme_yinyang),
YOTSUBA(MR.strings.theme_yotsuba),
// Deprecated
DARK_BLUE(null),

View File

@ -1,10 +1,11 @@
package eu.kanade.domain.ui.model
import eu.kanade.tachiyomi.R
import dev.icerock.moko.resources.StringResource
import tachiyomi.i18n.MR
enum class TabletUiMode(val titleResId: Int) {
AUTOMATIC(R.string.automatic_background),
ALWAYS(R.string.lock_always),
LANDSCAPE(R.string.landscape),
NEVER(R.string.lock_never),
enum class TabletUiMode(val titleRes: StringResource) {
AUTOMATIC(MR.strings.automatic_background),
ALWAYS(MR.strings.lock_always),
LANDSCAPE(MR.strings.landscape),
NEVER(MR.strings.lock_never),
}

View File

@ -14,7 +14,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.paging.LoadState
import androidx.paging.compose.LazyPagingItems
import eu.kanade.presentation.browse.components.BrowseSourceComfortableGrid
@ -23,17 +22,19 @@ import eu.kanade.presentation.browse.components.BrowseSourceEHentaiList
import eu.kanade.presentation.browse.components.BrowseSourceList
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.formattedMessage
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.Source
import exh.metadata.metadata.RaisedSearchMetadata
import exh.source.isEhBasedSource
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.StateFlow
import tachiyomi.core.i18n.localize
import tachiyomi.domain.library.model.LibraryDisplayMode
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.model.StubSource
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.EmptyScreenAction
import tachiyomi.presentation.core.screens.LoadingScreen
@ -71,7 +72,7 @@ fun BrowseSourceContent(
if (mangaList.itemCount > 0 && errorState != null && errorState is LoadState.Error) {
val result = snackbarHostState.showSnackbar(
message = getErrorMessage(errorState),
actionLabel = context.getString(R.string.action_retry),
actionLabel = context.localize(MR.strings.action_retry),
duration = SnackbarDuration.Indefinite,
)
when (result) {
@ -88,7 +89,7 @@ fun BrowseSourceContent(
actions = if (source is LocalSource /* SY --> */ && onLocalSourceHelpClick != null /* SY <-- */) {
persistentListOf(
EmptyScreenAction(
stringResId = R.string.local_source_help_guide,
stringRes = MR.strings.local_source_help_guide,
icon = Icons.AutoMirrored.Outlined.HelpOutline,
onClick = onLocalSourceHelpClick,
),
@ -96,7 +97,7 @@ fun BrowseSourceContent(
} else {
listOfNotNull(
EmptyScreenAction(
stringResId = R.string.action_retry,
stringRes = MR.strings.action_retry,
icon = Icons.Outlined.Refresh,
onClick = mangaList::refresh,
),
@ -191,7 +192,7 @@ internal fun MissingSourceScreen(
},
) { paddingValues ->
EmptyScreen(
message = stringResource(R.string.source_not_installed, source.toString()),
message = localize(MR.strings.source_not_installed, source.toString()),
modifier = Modifier.padding(paddingValues),
)
}

View File

@ -7,13 +7,13 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionFilterState
import eu.kanade.tachiyomi.util.system.LocaleHelper
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
@Composable
@ -25,7 +25,7 @@ fun ExtensionFilterScreen(
Scaffold(
topBar = { scrollBehavior ->
AppBar(
title = stringResource(R.string.label_extensions),
title = localize(MR.strings.label_extensions),
navigateUp = navigateUp,
scrollBehavior = scrollBehavior,
)
@ -33,7 +33,7 @@ fun ExtensionFilterScreen(
) { contentPadding ->
if (state.isEmpty) {
EmptyScreen(
textResource = R.string.empty_screen,
stringRes = MR.strings.empty_screen,
modifier = Modifier.padding(contentPadding),
)
return@Scaffold

View File

@ -7,9 +7,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.manga.components.BaseMangaListItem
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaScreenModel
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.screens.EmptyScreen
@ -33,7 +33,7 @@ fun MigrateMangaScreen(
) { contentPadding ->
if (state.isEmpty) {
EmptyScreen(
textResource = R.string.empty_screen,
stringRes = MR.strings.empty_screen,
modifier = Modifier.padding(contentPadding),
)
return@Scaffold

View File

@ -22,21 +22,21 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.presentation.browse.components.BaseSourceItem
import eu.kanade.presentation.browse.components.SourceIcon
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrateSourceScreenModel
import eu.kanade.tachiyomi.util.system.copyToClipboard
import tachiyomi.domain.source.model.Source
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.Badge
import tachiyomi.presentation.core.components.BadgeGroup
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.components.Scroller.STICKY_HEADER_KEY_PREFIX
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.presentation.core.theme.header
@ -58,7 +58,7 @@ fun MigrateSourceScreen(
when {
state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
state.isEmpty -> EmptyScreen(
textResource = R.string.information_empty_library,
stringRes = MR.strings.information_empty_library,
modifier = Modifier.padding(contentPadding),
)
else ->
@ -106,7 +106,7 @@ private fun MigrateSourceList(
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(R.string.migration_selection_prompt),
text = localize(MR.strings.migration_selection_prompt),
modifier = Modifier.weight(1f),
style = MaterialTheme.typography.header,
)
@ -115,11 +115,11 @@ private fun MigrateSourceList(
when (sortingMode) {
SetMigrateSorting.Mode.ALPHABETICAL -> Icon(
Icons.Outlined.SortByAlpha,
contentDescription = stringResource(R.string.action_sort_alpha),
contentDescription = localize(MR.strings.action_sort_alpha),
)
SetMigrateSorting.Mode.TOTAL -> Icon(
Icons.Outlined.Numbers,
contentDescription = stringResource(R.string.action_sort_count),
contentDescription = localize(MR.strings.action_sort_count),
)
}
}
@ -127,11 +127,11 @@ private fun MigrateSourceList(
when (sortingDirection) {
SetMigrateSorting.Direction.ASCENDING -> Icon(
Icons.Outlined.ArrowUpward,
contentDescription = stringResource(R.string.action_asc),
contentDescription = localize(MR.strings.action_asc),
)
SetMigrateSorting.Direction.DESCENDING -> Icon(
Icons.Outlined.ArrowDownward,
contentDescription = stringResource(R.string.action_desc),
contentDescription = localize(MR.strings.action_desc),
)
}
}
@ -216,7 +216,7 @@ private fun MigrateSourceItem(
if (source.isStub) {
Text(
modifier = Modifier.secondaryItemAlpha(),
text = stringResource(R.string.not_installed),
text = localize(MR.strings.not_installed),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall,

View File

@ -8,16 +8,16 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.browse.components.BaseSourceItem
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterScreenModel
import eu.kanade.tachiyomi.util.system.LocaleHelper
import tachiyomi.domain.source.model.Source
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
@Composable
@ -33,7 +33,7 @@ fun SourcesFilterScreen(
Scaffold(
topBar = { scrollBehavior ->
AppBar(
title = stringResource(R.string.label_sources),
title = localize(MR.strings.label_sources),
navigateUp = navigateUp,
scrollBehavior = scrollBehavior,
)
@ -41,7 +41,7 @@ fun SourcesFilterScreen(
) { contentPadding ->
if (state.isEmpty) {
EmptyScreen(
textResource = R.string.source_filter_empty_screen,
stringRes = MR.strings.source_filter_empty_screen,
modifier = Modifier.padding(contentPadding),
)
return@Scaffold

View File

@ -18,6 +18,8 @@ import androidx.compose.ui.window.DialogProperties
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.toast
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun RemoveMangaDialog(
@ -29,7 +31,7 @@ fun RemoveMangaDialog(
onDismissRequest = onDismissRequest,
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
confirmButton = {
@ -39,14 +41,14 @@ fun RemoveMangaDialog(
onConfirm()
},
) {
Text(text = stringResource(R.string.action_remove))
Text(text = localize(MR.strings.action_remove))
}
},
title = {
Text(text = stringResource(R.string.are_you_sure))
Text(text = localize(MR.strings.are_you_sure))
},
text = {
Text(text = stringResource(R.string.remove_manga, mangaToRemove.title))
Text(text = localize(MR.strings.remove_manga, mangaToRemove.title))
},
)
}

View File

@ -12,19 +12,19 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.AppBarTitle
import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.presentation.components.RadioMenuItem
import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.Source
import exh.source.anyIs
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.domain.library.model.LibraryDisplayMode
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.source.local.LocalSource
@Composable
@ -111,7 +111,7 @@ fun BrowseSourceToolbar(
if (isConfigurableSource) {
add(
AppBar.OverflowAction(
title = stringResource(R.string.action_settings),
title = localize(MR.strings.action_settings),
onClick = onSettingsClick,
),
)
@ -125,21 +125,21 @@ fun BrowseSourceToolbar(
onDismissRequest = { selectingDisplayMode = false },
) {
RadioMenuItem(
text = { Text(text = stringResource(R.string.action_display_comfortable_grid)) },
text = { Text(text = localize(MR.strings.action_display_comfortable_grid)) },
isChecked = displayMode == LibraryDisplayMode.ComfortableGrid,
) {
selectingDisplayMode = false
onDisplayModeChange(LibraryDisplayMode.ComfortableGrid)
}
RadioMenuItem(
text = { Text(text = stringResource(R.string.action_display_grid)) },
text = { Text(text = localize(MR.strings.action_display_grid)) },
isChecked = displayMode == LibraryDisplayMode.CompactGrid,
) {
selectingDisplayMode = false
onDisplayModeChange(LibraryDisplayMode.CompactGrid)
}
RadioMenuItem(
text = { Text(text = stringResource(R.string.action_display_list)) },
text = { Text(text = localize(MR.strings.action_display_list)) },
isChecked = displayMode == LibraryDisplayMode.List,
) {
selectingDisplayMode = false

View File

@ -13,15 +13,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.library.components.CommonMangaItemDefaults
import eu.kanade.presentation.library.components.MangaComfortableGridItem
import eu.kanade.tachiyomi.R
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.MangaCover
import tachiyomi.domain.manga.model.asMangaCover
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
@Composable
fun GlobalSearchCardRow(
@ -78,7 +78,7 @@ private fun MangaItem(
@Composable
private fun EmptyResultItem() {
Text(
text = stringResource(R.string.no_results_found),
text = localize(MR.strings.no_results_found),
modifier = Modifier
.padding(
horizontal = MaterialTheme.padding.medium,

View File

@ -23,11 +23,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
@Composable
fun GlobalSearchResultItem(
@ -112,7 +112,7 @@ fun GlobalSearchErrorResultItem(message: String?) {
Icon(imageVector = Icons.Outlined.Error, contentDescription = null)
Spacer(Modifier.height(4.dp))
Text(
text = message ?: stringResource(R.string.unknown_error),
text = message ?: localize(MR.strings.unknown_error),
textAlign = TextAlign.Center,
)
}

View File

@ -26,11 +26,11 @@ import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
@Composable
fun GlobalSearchToolbar(
@ -85,7 +85,7 @@ fun GlobalSearchToolbar(
)
},
label = {
Text(text = stringResource(id = R.string.pinned_sources))
Text(text = localize(MR.strings.pinned_sources))
},
)
FilterChip(
@ -100,7 +100,7 @@ fun GlobalSearchToolbar(
)
},
label = {
Text(text = stringResource(id = R.string.all))
Text(text = localize(MR.strings.all))
},
)
@ -118,7 +118,7 @@ fun GlobalSearchToolbar(
)
},
label = {
Text(text = stringResource(id = R.string.has_results))
Text(text = localize(MR.strings.has_results))
},
)
}

View File

@ -2,19 +2,20 @@ package eu.kanade.presentation.category
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import tachiyomi.core.i18n.localize
import tachiyomi.domain.category.model.Category
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
val Category.visualName: String
@Composable
get() = when {
isSystemCategory -> stringResource(R.string.label_default)
isSystemCategory -> localize(MR.strings.label_default)
else -> name
}
fun Category.visualName(context: Context): String =
when {
isSystemCategory -> context.getString(R.string.label_default)
isSystemCategory -> context.localize(MR.strings.label_default)
else -> name
}

View File

@ -12,18 +12,18 @@ import androidx.compose.material.icons.outlined.SortByAlpha
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.category.components.CategoryFloatingActionButton
import eu.kanade.presentation.category.components.CategoryListItem
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.category.CategoryScreenState
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.domain.category.model.Category
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.util.plus
@ -42,13 +42,13 @@ fun CategoryScreen(
Scaffold(
topBar = { scrollBehavior ->
AppBar(
title = stringResource(R.string.action_edit_categories),
title = localize(MR.strings.action_edit_categories),
navigateUp = navigateUp,
actions = {
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_sort),
title = localize(MR.strings.action_sort),
icon = Icons.Outlined.SortByAlpha,
onClick = onClickSortAlphabetically,
),
@ -67,7 +67,7 @@ fun CategoryScreen(
) { paddingValues ->
if (state.isEmpty) {
EmptyScreen(
textResource = R.string.information_empty_category,
stringRes = MR.strings.information_empty_category,
modifier = Modifier.padding(paddingValues),
)
return@Scaffold

View File

@ -6,9 +6,9 @@ import androidx.compose.material.icons.outlined.Add
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrollingUp
@ -18,7 +18,7 @@ fun CategoryFloatingActionButton(
onCreate: () -> Unit,
) {
ExtendedFloatingActionButton(
text = { Text(text = stringResource(R.string.action_add)) },
text = { Text(text = localize(MR.strings.action_add)) },
icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = null) },
onClick = onCreate,
expanded = lazyListState.isScrollingUp() || lazyListState.isScrolledToEnd(),

View File

@ -20,10 +20,10 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import tachiyomi.domain.category.model.Category
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
@Composable
fun CategoryListItem(
@ -74,11 +74,11 @@ fun CategoryListItem(
IconButton(onClick = onRename) {
Icon(
imageVector = Icons.Outlined.Edit,
contentDescription = stringResource(R.string.action_rename_category),
contentDescription = localize(MR.strings.action_rename_category),
)
}
IconButton(onClick = onDelete) {
Icon(imageVector = Icons.Outlined.Delete, contentDescription = stringResource(R.string.action_delete))
Icon(imageVector = Icons.Outlined.Delete, contentDescription = localize(MR.strings.action_delete))
}
}
}

View File

@ -52,6 +52,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.ImmutableList
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.clearFocusOnSoftKeyboardHide
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
import tachiyomi.presentation.core.util.secondaryItemAlpha
@ -133,7 +135,7 @@ fun AppBar(
IconButton(onClick = onCancelActionMode) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = stringResource(R.string.action_cancel),
contentDescription = localize(MR.strings.action_cancel),
)
}
} else {
@ -253,7 +255,7 @@ fun AppBarActions(
/**
* @param searchEnabled Set to false if you don't want to show search action.
* @param searchQuery If null, use normal toolbar.
* @param placeholderText If null, [R.string.action_search_hint] is used.
* @param placeholderText If null, [MR.strings.action_search_hint] is used.
*/
@Composable
fun SearchToolbar(
@ -317,7 +319,7 @@ fun SearchToolbar(
placeholder = {
Text(
modifier = Modifier.secondaryItemAlpha(),
text = (placeholderText ?: stringResource(R.string.action_search_hint)),
text = (placeholderText ?: localize(MR.strings.action_search_hint)),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.titleMedium.copy(
@ -342,7 +344,7 @@ fun SearchToolbar(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
tooltip = {
PlainTooltip {
Text(stringResource(R.string.action_search))
Text(localize(MR.strings.action_search))
}
},
state = rememberTooltipState(),
@ -352,7 +354,7 @@ fun SearchToolbar(
) {
Icon(
Icons.Outlined.Search,
contentDescription = stringResource(R.string.action_search),
contentDescription = localize(MR.strings.action_search),
)
}
}
@ -361,7 +363,7 @@ fun SearchToolbar(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
tooltip = {
PlainTooltip {
Text(stringResource(R.string.action_reset))
Text(localize(MR.strings.action_reset))
}
},
state = rememberTooltipState(),
@ -374,7 +376,7 @@ fun SearchToolbar(
) {
Icon(
Icons.Outlined.Close,
contentDescription = stringResource(R.string.action_reset),
contentDescription = localize(MR.strings.action_reset),
)
}
}

View File

@ -1,6 +1,5 @@
package eu.kanade.presentation.components
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
@ -26,13 +25,14 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.util.fastMaxBy
import eu.kanade.tachiyomi.R
import dev.icerock.moko.resources.StringResource
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
val DownloadedOnlyBannerBackgroundColor
@Composable get() = MaterialTheme.colorScheme.tertiary
@ -43,11 +43,11 @@ val IndexingBannerBackgroundColor
@Composable
fun WarningBanner(
@StringRes textRes: Int,
textRes: StringResource,
modifier: Modifier = Modifier,
) {
Text(
text = stringResource(textRes),
text = localize(textRes),
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.error)
@ -127,7 +127,7 @@ fun AppStateBanners(
@Composable
private fun DownloadedOnlyModeBanner(modifier: Modifier = Modifier) {
Text(
text = stringResource(R.string.label_downloaded_only),
text = localize(MR.strings.label_downloaded_only),
modifier = Modifier
.background(DownloadedOnlyBannerBackgroundColor)
.fillMaxWidth()
@ -142,7 +142,7 @@ private fun DownloadedOnlyModeBanner(modifier: Modifier = Modifier) {
@Composable
private fun IncognitoModeBanner(modifier: Modifier = Modifier) {
Text(
text = stringResource(R.string.pref_incognito_mode),
text = localize(MR.strings.pref_incognito_mode),
modifier = Modifier
.background(IncognitoModeBannerBackgroundColor)
.fillMaxWidth()
@ -173,7 +173,7 @@ private fun IndexingDownloadBanner(modifier: Modifier = Modifier) {
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.download_notifier_cache_renewal),
text = localize(MR.strings.download_notifier_cache_renewal),
color = MaterialTheme.colorScheme.onSecondary,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.labelMedium,

View File

@ -3,10 +3,10 @@ package eu.kanade.presentation.components
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.i18n.localizePlural
@Composable
fun DownloadDropdownMenu(
@ -19,11 +19,11 @@ fun DownloadDropdownMenu(
onDismissRequest = onDismissRequest,
) {
listOfNotNull(
DownloadAction.NEXT_1_CHAPTER to pluralStringResource(R.plurals.download_amount, 1, 1),
DownloadAction.NEXT_5_CHAPTERS to pluralStringResource(R.plurals.download_amount, 5, 5),
DownloadAction.NEXT_10_CHAPTERS to pluralStringResource(R.plurals.download_amount, 10, 10),
DownloadAction.NEXT_25_CHAPTERS to pluralStringResource(R.plurals.download_amount, 25, 25),
DownloadAction.UNREAD_CHAPTERS to stringResource(R.string.download_unread),
DownloadAction.NEXT_1_CHAPTER to localizePlural(MR.plurals.download_amount, 1, 1),
DownloadAction.NEXT_5_CHAPTERS to localizePlural(MR.plurals.download_amount, 5, 5),
DownloadAction.NEXT_10_CHAPTERS to localizePlural(MR.plurals.download_amount, 10, 10),
DownloadAction.NEXT_25_CHAPTERS to localizePlural(MR.plurals.download_amount, 25, 25),
DownloadAction.UNREAD_CHAPTERS to localize(MR.strings.download_unread),
).map { (downloadAction, string) ->
DropdownMenuItem(
text = { Text(text = string) },

View File

@ -15,11 +15,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.PopupProperties
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import androidx.compose.material3.DropdownMenu as ComposeDropdownMenu
@Composable
@ -54,13 +54,13 @@ fun RadioMenuItem(
if (isChecked) {
Icon(
imageVector = Icons.Outlined.RadioButtonChecked,
contentDescription = stringResource(R.string.selected),
contentDescription = localize(MR.strings.selected),
tint = MaterialTheme.colorScheme.primary,
)
} else {
Icon(
imageVector = Icons.Outlined.RadioButtonUnchecked,
contentDescription = stringResource(R.string.not_selected),
contentDescription = localize(MR.strings.not_selected),
)
}
},

View File

@ -2,14 +2,13 @@ package eu.kanade.presentation.components
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
import androidx.compose.material.icons.outlined.HelpOutline
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.PreviewLightDark
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.EmptyScreenAction
@ -19,7 +18,7 @@ private fun NoActionPreview() {
TachiyomiTheme {
Surface {
EmptyScreen(
textResource = R.string.empty_screen,
stringRes = MR.strings.empty_screen,
)
}
}
@ -31,15 +30,15 @@ private fun WithActionPreview() {
TachiyomiTheme {
Surface {
EmptyScreen(
textResource = R.string.empty_screen,
stringRes = MR.strings.empty_screen,
actions = persistentListOf(
EmptyScreenAction(
stringResId = R.string.action_retry,
stringRes = MR.strings.action_retry,
icon = Icons.Outlined.Refresh,
onClick = {},
),
EmptyScreenAction(
stringResId = R.string.getting_started_guide,
stringRes = MR.strings.getting_started_guide,
icon = Icons.AutoMirrored.Outlined.HelpOutline,
onClick = {},
),

View File

@ -24,14 +24,14 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEachIndexed
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.launch
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.HorizontalPager
import tachiyomi.presentation.core.components.material.TabText
import tachiyomi.presentation.core.i18n.localize
object TabbedDialogPaddings {
val Horizontal = 24.dp
@ -94,7 +94,7 @@ private fun MoreMenu(
IconButton(onClick = { expanded = true }) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = stringResource(R.string.label_more),
contentDescription = localize(MR.strings.label_more),
)
}
DropdownMenu(

View File

@ -1,6 +1,5 @@
package eu.kanade.presentation.components
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
@ -20,17 +19,18 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.StringResource
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch
import tachiyomi.presentation.core.components.HorizontalPager
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.TabText
import tachiyomi.presentation.core.i18n.localize
@Composable
fun TabbedScreen(
@StringRes titleRes: Int,
titleRes: StringResource,
tabs: ImmutableList<TabContent>,
startIndex: Int? = null,
searchQuery: String? = null,
@ -52,7 +52,7 @@ fun TabbedScreen(
val searchEnabled = tab.searchEnabled
SearchToolbar(
titleContent = { AppBarTitle(stringResource(titleRes)) },
titleContent = { AppBarTitle(localize(titleRes)) },
searchEnabled = searchEnabled,
searchQuery = if (searchEnabled) searchQuery else null,
onChangeSearchQuery = onChangeSearchQuery,
@ -75,7 +75,7 @@ fun TabbedScreen(
Tab(
selected = state.currentPage == index,
onClick = { scope.launch { state.animateScrollToPage(index) } },
text = { TabText(text = stringResource(tab.titleRes), badgeCount = tab.badgeNumber) },
text = { TabText(text = localize(tab.titleRes), badgeCount = tab.badgeNumber) },
unselectedContentColor = MaterialTheme.colorScheme.onSurface,
)
}
@ -96,7 +96,7 @@ fun TabbedScreen(
}
data class TabContent(
@StringRes val titleRes: Int,
val titleRes: StringResource,
val badgeNumber: Int? = null,
val searchEnabled: Boolean = false,
val actions: ImmutableList<AppBar.Action> = persistentListOf(),

View File

@ -13,13 +13,13 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.CrashLogUtil
import kotlinx.coroutines.launch
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.InfoScreen
@Composable
@ -32,15 +32,15 @@ fun CrashScreen(
InfoScreen(
icon = Icons.Outlined.BugReport,
headingText = stringResource(R.string.crash_screen_title),
subtitleText = stringResource(R.string.crash_screen_description, stringResource(R.string.app_name)),
acceptText = stringResource(R.string.pref_dump_crash_logs),
headingText = localize(MR.strings.crash_screen_title),
subtitleText = localize(MR.strings.crash_screen_description, localize(MR.strings.app_name)),
acceptText = localize(MR.strings.pref_dump_crash_logs),
onAcceptClick = {
scope.launch {
CrashLogUtil(context).dumpLogs()
}
},
rejectText = stringResource(R.string.crash_screen_restart_application),
rejectText = localize(MR.strings.crash_screen_restart_application),
onRejectClick = onRestartClick,
) {
Box(

View File

@ -10,7 +10,6 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import eu.kanade.domain.ui.UiPreferences
@ -21,13 +20,14 @@ import eu.kanade.presentation.components.RelativeDateHeader
import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.presentation.history.components.HistoryItem
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.history.HistoryScreenModel
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.core.preference.InMemoryPreferenceStore
import tachiyomi.domain.history.model.HistoryWithRelations
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.LoadingScreen
import uy.kohesive.injekt.Injekt
@ -47,14 +47,14 @@ fun HistoryScreen(
Scaffold(
topBar = { scrollBehavior ->
SearchToolbar(
titleContent = { AppBarTitle(stringResource(R.string.history)) },
titleContent = { AppBarTitle(localize(MR.strings.history)) },
searchQuery = state.searchQuery,
onChangeSearchQuery = onSearchQueryChange,
actions = {
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.pref_clear_history),
title = localize(MR.strings.pref_clear_history),
icon = Icons.Outlined.DeleteSweep,
onClick = {
onDialogChange(HistoryScreenModel.Dialog.DeleteAll)
@ -73,12 +73,12 @@ fun HistoryScreen(
LoadingScreen(Modifier.padding(contentPadding))
} else if (it.isEmpty()) {
val msg = if (!state.searchQuery.isNullOrEmpty()) {
R.string.no_results_found
MR.strings.no_results_found
} else {
R.string.information_no_recent_manga
MR.strings.information_no_recent_manga
}
EmptyScreen(
textResource = msg,
stringRes = msg,
modifier = Modifier.padding(contentPadding),
)
} else {

View File

@ -10,12 +10,12 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.i18n.localize
@Composable
fun HistoryDeleteDialog(
@ -26,16 +26,16 @@ fun HistoryDeleteDialog(
AlertDialog(
title = {
Text(text = stringResource(R.string.action_remove))
Text(text = localize(MR.strings.action_remove))
},
text = {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(text = stringResource(R.string.dialog_with_checkbox_remove_description))
Text(text = localize(MR.strings.dialog_with_checkbox_remove_description))
LabeledCheckbox(
label = stringResource(R.string.dialog_with_checkbox_reset),
label = localize(MR.strings.dialog_with_checkbox_reset),
checked = removeEverything,
onCheckedChange = { removeEverything = it },
)
@ -47,12 +47,12 @@ fun HistoryDeleteDialog(
onDelete(removeEverything)
onDismissRequest()
}) {
Text(text = stringResource(R.string.action_remove))
Text(text = localize(MR.strings.action_remove))
}
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
)
@ -65,10 +65,10 @@ fun HistoryDeleteAllDialog(
) {
AlertDialog(
title = {
Text(text = stringResource(R.string.action_remove_everything))
Text(text = localize(MR.strings.action_remove_everything))
},
text = {
Text(text = stringResource(R.string.clear_history_confirmation))
Text(text = localize(MR.strings.clear_history_confirmation))
},
onDismissRequest = onDismissRequest,
confirmButton = {
@ -76,12 +76,12 @@ fun HistoryDeleteAllDialog(
onDelete()
onDismissRequest()
}) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
)

View File

@ -17,7 +17,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
@ -26,10 +25,11 @@ import androidx.compose.ui.unit.dp
import eu.kanade.presentation.manga.components.MangaCover
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.presentation.util.formatChapterNumber
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.lang.toTimestampString
import tachiyomi.domain.history.model.HistoryWithRelations
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
private val HistoryItemHeight = 96.dp
@ -69,8 +69,8 @@ fun HistoryItem(
val readAt = remember { history.readAt?.toTimestampString() ?: "" }
Text(
text = if (history.chapterNumber > -1) {
stringResource(
R.string.recent_manga_time,
localize(
MR.strings.recent_manga_time,
formatChapterNumber(history.chapterNumber),
readAt,
)
@ -85,7 +85,7 @@ fun HistoryItem(
IconButton(onClick = onClickDelete) {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = stringResource(R.string.action_delete),
contentDescription = localize(MR.strings.action_delete),
tint = MaterialTheme.colorScheme.onSurface,
)
}

View File

@ -9,10 +9,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import dev.icerock.moko.resources.StringResource
import tachiyomi.core.preference.CheckboxState
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.i18n.localize
@Composable
fun DeleteLibraryMangaDialog(
@ -22,10 +23,10 @@ fun DeleteLibraryMangaDialog(
) {
var list by remember {
mutableStateOf(
buildList<CheckboxState.State<Int>> {
add(CheckboxState.State.None(R.string.manga_from_library))
buildList<CheckboxState.State<StringResource>> {
add(CheckboxState.State.None(MR.strings.manga_from_library))
if (!containsLocalManga) {
add(CheckboxState.State.None(R.string.downloaded_chapters))
add(CheckboxState.State.None(MR.strings.downloaded_chapters))
}
},
)
@ -34,7 +35,7 @@ fun DeleteLibraryMangaDialog(
onDismissRequest = onDismissRequest,
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
confirmButton = {
@ -48,23 +49,23 @@ fun DeleteLibraryMangaDialog(
)
},
) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
title = {
Text(text = stringResource(R.string.action_remove))
Text(text = localize(MR.strings.action_remove))
},
text = {
Column {
list.forEach { state ->
LabeledCheckbox(
label = stringResource(state.value),
label = localize(state.value),
checked = state.isChecked,
onCheckedChange = {
val index = list.indexOf(state)
if (index != -1) {
val mutableList = list.toMutableList()
mutableList[index] = state.next() as CheckboxState.State<Int>
mutableList[index] = state.next() as CheckboxState.State<StringResource>
list = mutableList.toList()
}
},

View File

@ -33,14 +33,14 @@ import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.presentation.manga.components.MangaCover
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.BadgeGroup
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.selectedBackground
object CommonMangaItemDefaults {
@ -378,7 +378,7 @@ private fun ContinueReadingButton(
) {
Icon(
imageVector = Icons.Filled.PlayArrow,
contentDescription = stringResource(R.string.action_resume),
contentDescription = localize(MR.strings.action_resume),
modifier = Modifier.size(16.dp),
)
}

View File

@ -4,9 +4,9 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.zIndex
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
internal fun GlobalSearchItem(
@ -19,7 +19,7 @@ internal fun GlobalSearchItem(
onClick = onClick,
) {
Text(
text = stringResource(R.string.action_global_search_query, searchQuery),
text = localize(MR.strings.action_global_search_query, searchQuery),
modifier = Modifier.zIndex(99f),
)
}

View File

@ -18,10 +18,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import eu.kanade.core.preference.PreferenceMutableState
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.library.LibraryItem
import tachiyomi.domain.library.model.LibraryDisplayMode
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.HorizontalPager
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.util.plus
@ -124,9 +124,9 @@ private fun LibraryPagerEmptyScreen(
onGlobalSearchClicked: () -> Unit,
) {
val msg = when {
!searchQuery.isNullOrEmpty() -> R.string.no_results_found
hasActiveFilters -> R.string.error_no_match
else -> R.string.information_no_manga_category
!searchQuery.isNullOrEmpty() -> MR.strings.no_results_found
hasActiveFilters -> MR.strings.error_no_match
else -> MR.strings.information_no_manga_category
}
Column(
@ -146,7 +146,7 @@ private fun LibraryPagerEmptyScreen(
}
EmptyScreen(
textResource = msg,
stringRes = msg,
modifier = Modifier.weight(1f),
)
}

View File

@ -14,15 +14,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.sp
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.Pill
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.theme.active
@Composable
@ -107,21 +107,21 @@ private fun LibraryRegularToolbar(
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_filter),
title = localize(MR.strings.action_filter),
icon = Icons.Outlined.FilterList,
iconTint = filterTint,
onClick = onClickFilter,
),
AppBar.OverflowAction(
title = stringResource(R.string.action_update_library),
title = localize(MR.strings.action_update_library),
onClick = onClickGlobalUpdate,
),
AppBar.OverflowAction(
title = stringResource(R.string.action_update_category),
title = localize(MR.strings.action_update_category),
onClick = onClickRefresh,
),
AppBar.OverflowAction(
title = stringResource(R.string.action_open_random_manga),
title = localize(MR.strings.action_open_random_manga),
onClick = onClickOpenRandomManga,
),
@ -156,12 +156,12 @@ private fun LibrarySelectionToolbar(
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_select_all),
title = localize(MR.strings.action_select_all),
icon = Icons.Outlined.SelectAll,
onClick = onClickSelectAll,
),
AppBar.Action(
title = stringResource(R.string.action_select_inverse),
title = localize(MR.strings.action_select_inverse),
icon = Icons.Outlined.FlipToBack,
onClick = onClickInvertSelection,
),

View File

@ -25,20 +25,20 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.domain.manga.model.downloadedFilter
import eu.kanade.domain.manga.model.forceDownloaded
import eu.kanade.presentation.components.TabbedDialog
import eu.kanade.presentation.components.TabbedDialogPaddings
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.core.preference.TriState
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.components.RadioItem
import tachiyomi.presentation.core.components.SortItem
import tachiyomi.presentation.core.components.TriStateItem
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.theme.active
@Composable
@ -66,20 +66,20 @@ fun ChapterSettingsDialog(
TabbedDialog(
onDismissRequest = onDismissRequest,
tabTitles = persistentListOf(
stringResource(R.string.action_filter),
stringResource(R.string.action_sort),
stringResource(R.string.action_display),
localize(MR.strings.action_filter),
localize(MR.strings.action_sort),
localize(MR.strings.action_display),
),
tabOverflowMenuContent = { closeMenu ->
DropdownMenuItem(
text = { Text(stringResource(R.string.set_chapter_settings_as_default)) },
text = { Text(localize(MR.strings.set_chapter_settings_as_default)) },
onClick = {
showSetAsDefaultDialog = true
closeMenu()
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.action_reset)) },
text = { Text(localize(MR.strings.action_reset)) },
onClick = {
onResetToDefault()
closeMenu()
@ -136,17 +136,17 @@ private fun ColumnScope.FilterPage(
onScanlatorFilterClicked: (() -> Unit),
) {
TriStateItem(
label = stringResource(R.string.label_downloaded),
label = localize(MR.strings.label_downloaded),
state = downloadFilter,
onClick = onDownloadFilterChanged,
)
TriStateItem(
label = stringResource(R.string.action_filter_unread),
label = localize(MR.strings.action_filter_unread),
state = unreadFilter,
onClick = onUnreadFilterChanged,
)
TriStateItem(
label = stringResource(R.string.action_filter_bookmarked),
label = localize(MR.strings.action_filter_bookmarked),
state = bookmarkedFilter,
onClick = onBookmarkedFilterChanged,
)
@ -179,7 +179,7 @@ fun ScanlatorFilterItem(
},
)
Text(
text = stringResource(R.string.scanlator),
text = localize(MR.strings.scanlator),
style = MaterialTheme.typography.bodyMedium,
)
}
@ -192,13 +192,13 @@ private fun ColumnScope.SortPage(
onItemSelected: (Long) -> Unit,
) {
listOf(
R.string.sort_by_source to Manga.CHAPTER_SORTING_SOURCE,
R.string.sort_by_number to Manga.CHAPTER_SORTING_NUMBER,
R.string.sort_by_upload_date to Manga.CHAPTER_SORTING_UPLOAD_DATE,
R.string.action_sort_alpha to Manga.CHAPTER_SORTING_ALPHABET,
MR.strings.sort_by_source to Manga.CHAPTER_SORTING_SOURCE,
MR.strings.sort_by_number to Manga.CHAPTER_SORTING_NUMBER,
MR.strings.sort_by_upload_date to Manga.CHAPTER_SORTING_UPLOAD_DATE,
MR.strings.action_sort_alpha to Manga.CHAPTER_SORTING_ALPHABET,
).map { (titleRes, mode) ->
SortItem(
label = stringResource(titleRes),
label = localize(titleRes),
sortDescending = sortDescending.takeIf { sortingMode == mode },
onClick = { onItemSelected(mode) },
)
@ -211,11 +211,11 @@ private fun ColumnScope.DisplayPage(
onItemSelected: (Long) -> Unit,
) {
listOf(
R.string.show_title to Manga.CHAPTER_DISPLAY_NAME,
R.string.show_chapter_number to Manga.CHAPTER_DISPLAY_NUMBER,
MR.strings.show_title to Manga.CHAPTER_DISPLAY_NAME,
MR.strings.show_chapter_number to Manga.CHAPTER_DISPLAY_NUMBER,
).map { (titleRes, mode) ->
RadioItem(
label = stringResource(titleRes),
label = localize(titleRes),
selected = displayMode == mode,
onClick = { onItemSelected(mode) },
)
@ -231,15 +231,15 @@ private fun SetAsDefaultDialog(
AlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(text = stringResource(R.string.chapter_settings)) },
title = { Text(text = localize(MR.strings.chapter_settings)) },
text = {
Column(
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(text = stringResource(R.string.confirm_set_chapter_settings))
Text(text = localize(MR.strings.confirm_set_chapter_settings))
LabeledCheckbox(
label = stringResource(R.string.also_set_chapter_settings_for_library),
label = localize(MR.strings.also_set_chapter_settings_for_library),
checked = optionalChecked,
onCheckedChange = { optionalChecked = it },
)
@ -247,7 +247,7 @@ private fun SetAsDefaultDialog(
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
confirmButton = {
@ -257,7 +257,7 @@ private fun SetAsDefaultDialog(
onDismissRequest()
},
) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
)

View File

@ -8,9 +8,9 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun DuplicateMangaDialog(
@ -21,10 +21,10 @@ fun DuplicateMangaDialog(
AlertDialog(
onDismissRequest = onDismissRequest,
title = {
Text(text = stringResource(R.string.are_you_sure))
Text(text = localize(MR.strings.are_you_sure))
},
text = {
Text(text = stringResource(R.string.confirm_add_duplicate_manga))
Text(text = localize(MR.strings.confirm_add_duplicate_manga))
},
confirmButton = {
FlowRow(
@ -36,13 +36,13 @@ fun DuplicateMangaDialog(
onOpenManga()
},
) {
Text(text = stringResource(R.string.action_show_manga))
Text(text = localize(MR.strings.action_show_manga))
}
Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
TextButton(
onClick = {
@ -50,7 +50,7 @@ fun DuplicateMangaDialog(
onConfirm()
},
) {
Text(text = stringResource(R.string.action_add))
Text(text = localize(MR.strings.action_add))
}
}
},

View File

@ -44,7 +44,6 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastMap
@ -61,7 +60,6 @@ import eu.kanade.presentation.manga.components.MissingChapterCountListItem
import eu.kanade.presentation.manga.components.PagePreviews
import eu.kanade.presentation.manga.components.SearchMetadataChips
import eu.kanade.presentation.util.formatChapterNumber
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.getNameForMangaInfo
@ -94,11 +92,13 @@ import tachiyomi.domain.chapter.service.missingChaptersCount
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.model.StubSource
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.TwoPanelBox
import tachiyomi.presentation.core.components.VerticalFastScroller
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
import tachiyomi.presentation.core.components.material.PullRefresh
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrollingUp
import java.text.DateFormat
@ -422,7 +422,7 @@ private fun MangaScreenSmallImpl(
val isReading = remember(state.chapters) {
state.chapters.fastAny { it.chapter.read }
}
Text(text = stringResource(if (isReading) R.string.action_resume else R.string.action_start))
Text(text = localize(if (isReading) MR.strings.action_resume else MR.strings.action_start))
},
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
onClick = onContinueReading,
@ -758,7 +758,7 @@ fun MangaScreenLargeImpl(
state.chapters.fastAny { it.chapter.read }
}
Text(
text = stringResource(if (isReading) R.string.action_resume else R.string.action_start),
text = localize(if (isReading) MR.strings.action_resume else MR.strings.action_start),
)
},
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
@ -977,8 +977,8 @@ private fun LazyListScope.sharedChapterItems(
is ChapterList.Item -> {
MangaChapterListItem(
title = if (manga.displayMode == Manga.CHAPTER_DISPLAY_NUMBER) {
stringResource(
R.string.display_mode_chapter,
localize(
MR.strings.display_mode_chapter,
formatChapterNumber(item.chapter.chapterNumber),
)
} else {
@ -1002,8 +1002,8 @@ private fun LazyListScope.sharedChapterItems(
readProgress = item.chapter.lastPageRead
.takeIf { /* SY --> */(!item.chapter.read || alwaysShowReadingProgress)/* SY <-- */ && it > 0L }
?.let {
stringResource(
R.string.chapter_progress,
localize(
MR.strings.chapter_progress,
it + 1,
)
},

View File

@ -29,13 +29,14 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.IconButtonTokens
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.secondaryItemAlpha
enum class ChapterDownloadAction {
@ -98,7 +99,7 @@ private fun NotDownloadedIndicator(
) {
Icon(
painter = painterResource(R.drawable.ic_download_chapter_24dp),
contentDescription = stringResource(R.string.manga_download),
contentDescription = localize(MR.strings.manga_download),
modifier = Modifier.size(IndicatorSize),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
@ -155,14 +156,14 @@ private fun DownloadingIndicator(
}
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_start_downloading_now)) },
text = { Text(text = localize(MR.strings.action_start_downloading_now)) },
onClick = {
onClick(ChapterDownloadAction.START_NOW)
isMenuExpanded = false
},
)
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_cancel)) },
text = { Text(text = localize(MR.strings.action_cancel)) },
onClick = {
onClick(ChapterDownloadAction.CANCEL)
isMenuExpanded = false
@ -203,7 +204,7 @@ private fun DownloadedIndicator(
)
DropdownMenu(expanded = isMenuExpanded, onDismissRequest = { isMenuExpanded = false }) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_delete)) },
text = { Text(text = localize(MR.strings.action_delete)) },
onClick = {
onClick(ChapterDownloadAction.DELETE)
isMenuExpanded = false
@ -231,7 +232,7 @@ private fun ErrorIndicator(
) {
Icon(
imageVector = Icons.Outlined.ErrorOutline,
contentDescription = stringResource(R.string.chapter_error),
contentDescription = localize(MR.strings.chapter_error),
modifier = Modifier.size(IndicatorSize),
tint = MaterialTheme.colorScheme.error,
)

View File

@ -9,12 +9,12 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.i18n.localizePlural
@Composable
fun ChapterHeader(
@ -35,9 +35,9 @@ fun ChapterHeader(
) {
Text(
text = if (chapterCount == null) {
stringResource(R.string.chapters)
localize(MR.strings.chapters)
} else {
pluralStringResource(id = R.plurals.manga_num_chapters, count = chapterCount, chapterCount)
localizePlural(MR.plurals.manga_num_chapters, count = chapterCount, chapterCount)
},
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onBackground,
@ -54,7 +54,7 @@ private fun MissingChaptersWarning(count: Int) {
}
Text(
text = pluralStringResource(id = R.plurals.missing_chapters, count = count, count),
text = localizePlural(MR.plurals.missing_chapters, count = count, count),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodySmall,

View File

@ -42,23 +42,22 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import me.saket.swipe.SwipeableActionsBox
import me.saket.swipe.rememberSwipeableActionsState
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.ReadItemAlpha
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.selectedBackground
import kotlin.math.absoluteValue
@Composable
fun MangaChapterListItem(
modifier: Modifier = Modifier,
title: String,
date: String?,
readProgress: String?,
@ -78,6 +77,7 @@ fun MangaChapterListItem(
onClick: () -> Unit,
onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
modifier: Modifier = Modifier,
) {
val haptic = LocalHapticFeedback.current
val density = LocalDensity.current
@ -146,7 +146,7 @@ fun MangaChapterListItem(
if (!read) {
Icon(
imageVector = Icons.Filled.Circle,
contentDescription = stringResource(R.string.unread),
contentDescription = localize(MR.strings.unread),
modifier = Modifier
.height(8.dp)
.padding(end = 4.dp),
@ -156,7 +156,7 @@ fun MangaChapterListItem(
if (bookmark) {
Icon(
imageVector = Icons.Filled.Bookmark,
contentDescription = stringResource(R.string.action_filter_bookmarked),
contentDescription = localize(MR.strings.action_filter_bookmarked),
modifier = Modifier
.sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }),
tint = MaterialTheme.colorScheme.primary,

View File

@ -32,7 +32,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
@ -47,11 +46,12 @@ import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.presentation.manga.EditCoverAction
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.clickableNoIndication
@Composable
@ -85,7 +85,7 @@ fun MangaCoverDialog(
IconButton(onClick = onDismissRequest) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = stringResource(R.string.action_close),
contentDescription = localize(MR.strings.action_close),
)
}
}
@ -94,12 +94,12 @@ fun MangaCoverDialog(
AppBarActions(
actions = persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_share),
title = localize(MR.strings.action_share),
icon = Icons.Outlined.Share,
onClick = onShareClick,
),
AppBar.Action(
title = stringResource(R.string.action_save),
title = localize(MR.strings.action_save),
icon = Icons.Outlined.Save,
onClick = onSaveClick,
),
@ -119,7 +119,7 @@ fun MangaCoverDialog(
) {
Icon(
imageVector = Icons.Outlined.Edit,
contentDescription = stringResource(R.string.action_edit_cover),
contentDescription = localize(MR.strings.action_edit_cover),
)
}
DropdownMenu(
@ -128,14 +128,14 @@ fun MangaCoverDialog(
offset = DpOffset(8.dp, 0.dp),
) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_edit)) },
text = { Text(text = localize(MR.strings.action_edit)) },
onClick = {
onEditClick(EditCoverAction.EDIT)
expanded = false
},
)
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_delete)) },
text = { Text(text = localize(MR.strings.action_delete)) },
onClick = {
onEditClick(EditCoverAction.DELETE)
expanded = false

View File

@ -65,8 +65,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Constraints
@ -79,8 +77,11 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.system.copyToClipboard
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.TextButton
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.i18n.localizePlural
import tachiyomi.presentation.core.util.clickableNoIndication
import tachiyomi.presentation.core.util.secondaryItemAlpha
import kotlin.math.absoluteValue
@ -180,9 +181,9 @@ fun MangaActionRow(
Row(modifier = modifier.padding(start = 16.dp, top = 8.dp, end = 16.dp)) {
MangaActionButton(
title = if (favorite) {
stringResource(R.string.in_library)
localize(MR.strings.in_library)
} else {
stringResource(R.string.add_to_library)
localize(MR.strings.add_to_library)
},
icon = if (favorite) Icons.Filled.Favorite else Icons.Outlined.FavoriteBorder,
color = if (favorite) MaterialTheme.colorScheme.primary else defaultActionButtonColor,
@ -191,8 +192,8 @@ fun MangaActionRow(
)
if (onEditIntervalClicked != null && fetchInterval != null) {
MangaActionButton(
title = pluralStringResource(
id = R.plurals.day,
title = localizePlural(
MR.plurals.day,
count = fetchInterval.absoluteValue,
fetchInterval.absoluteValue,
),
@ -204,9 +205,9 @@ fun MangaActionRow(
if (onTrackingClicked != null) {
MangaActionButton(
title = if (trackingCount == 0) {
stringResource(R.string.manga_tracking_tab)
localize(MR.strings.manga_tracking_tab)
} else {
pluralStringResource(id = R.plurals.num_trackers, count = trackingCount, trackingCount)
localizePlural(MR.plurals.num_trackers, count = trackingCount, trackingCount)
},
icon = if (trackingCount == 0) Icons.Outlined.Sync else Icons.Outlined.Done,
color = if (trackingCount == 0) defaultActionButtonColor else MaterialTheme.colorScheme.primary,
@ -215,7 +216,7 @@ fun MangaActionRow(
}
if (onWebViewClicked != null) {
MangaActionButton(
title = stringResource(R.string.action_web_view),
title = localize(MR.strings.action_web_view),
icon = Icons.Outlined.Public,
color = defaultActionButtonColor,
onClick = onWebViewClicked,
@ -253,7 +254,7 @@ fun ExpandableMangaDescription(
mutableStateOf(defaultExpandState)
}
val desc =
description.takeIf { !it.isNullOrBlank() } ?: stringResource(R.string.description_placeholder)
description.takeIf { !it.isNullOrBlank() } ?: localize(MR.strings.description_placeholder)
val trimmedDescription = remember(desc) {
desc
.replace(whitespaceLineRegex, "\n")
@ -283,7 +284,7 @@ fun ExpandableMangaDescription(
onDismissRequest = { showMenu = false },
) {
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_search)) },
text = { Text(text = localize(MR.strings.action_search)) },
onClick = {
onTagSearch(tagSelected)
showMenu = false
@ -299,7 +300,7 @@ fun ExpandableMangaDescription(
)
// SY <--
DropdownMenuItem(
text = { Text(text = stringResource(R.string.action_copy_to_clipboard)) },
text = { Text(text = localize(MR.strings.action_copy_to_clipboard)) },
onClick = {
onCopyTagToClipboard(tagSelected)
showMenu = false
@ -378,7 +379,7 @@ private fun MangaAndSourceTitlesLarge(
MangaCover.Book(
modifier = Modifier.fillMaxWidth(0.65f),
data = coverDataProvider(),
contentDescription = stringResource(R.string.manga_cover),
contentDescription = localize(MR.strings.manga_cover),
onClick = onCoverClick,
)
Spacer(modifier = Modifier.height(16.dp))
@ -420,7 +421,7 @@ private fun MangaAndSourceTitlesSmall(
.sizeIn(maxWidth = 100.dp)
.align(Alignment.Top),
data = coverDataProvider(),
contentDescription = stringResource(R.string.manga_cover),
contentDescription = localize(MR.strings.manga_cover),
onClick = onCoverClick,
)
Column(
@ -452,7 +453,7 @@ private fun MangaContentInfo(
) {
val context = LocalContext.current
Text(
text = title.ifBlank { stringResource(R.string.unknown_title) },
text = title.ifBlank { localize(MR.strings.unknown_title) },
style = MaterialTheme.typography.titleLarge,
modifier = Modifier.clickableNoIndication(
onLongClick = {
@ -482,7 +483,7 @@ private fun MangaContentInfo(
)
Text(
text = author?.takeIf { it.isNotBlank() }
?: stringResource(R.string.unknown_author),
?: localize(MR.strings.unknown_author),
style = MaterialTheme.typography.titleSmall,
modifier = Modifier
.clickableNoIndication(
@ -548,13 +549,13 @@ private fun MangaContentInfo(
ProvideTextStyle(MaterialTheme.typography.bodyMedium) {
Text(
text = when (status) {
SManga.ONGOING.toLong() -> stringResource(R.string.ongoing)
SManga.COMPLETED.toLong() -> stringResource(R.string.completed)
SManga.LICENSED.toLong() -> stringResource(R.string.licensed)
SManga.PUBLISHING_FINISHED.toLong() -> stringResource(R.string.publishing_finished)
SManga.CANCELLED.toLong() -> stringResource(R.string.cancelled)
SManga.ON_HIATUS.toLong() -> stringResource(R.string.on_hiatus)
else -> stringResource(R.string.unknown)
SManga.ONGOING.toLong() -> localize(MR.strings.ongoing)
SManga.COMPLETED.toLong() -> localize(MR.strings.completed)
SManga.LICENSED.toLong() -> localize(MR.strings.licensed)
SManga.PUBLISHING_FINISHED.toLong() -> localize(MR.strings.publishing_finished)
SManga.CANCELLED.toLong() -> localize(MR.strings.cancelled)
SManga.ON_HIATUS.toLong() -> localize(MR.strings.on_hiatus)
else -> localize(MR.strings.unknown)
},
overflow = TextOverflow.Ellipsis,
maxLines = 1,
@ -628,8 +629,8 @@ private fun MangaSummary(
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_caret_down)
Icon(
painter = rememberAnimatedVectorPainter(image, !expanded),
contentDescription = stringResource(
if (expanded) R.string.manga_info_collapse else R.string.manga_info_expand,
contentDescription = localize(
if (expanded) MR.strings.manga_info_collapse else MR.strings.manga_info_expand,
),
tint = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.background(Brush.radialGradient(colors = colors.asReversed())),

View File

@ -21,7 +21,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.components.AppBar
@ -29,8 +28,9 @@ import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.DownloadDropdownMenu
import eu.kanade.presentation.components.UpIcon
import eu.kanade.presentation.manga.DownloadAction
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.theme.active
@Composable
@ -81,12 +81,12 @@ fun MangaToolbar(
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_select_all),
title = localize(MR.strings.action_select_all),
icon = Icons.Outlined.SelectAll,
onClick = onSelectAll,
),
AppBar.Action(
title = stringResource(R.string.action_select_inverse),
title = localize(MR.strings.action_select_inverse),
icon = Icons.Outlined.FlipToBack,
onClick = onInvertSelection,
),
@ -110,7 +110,7 @@ fun MangaToolbar(
if (onClickDownload != null) {
add(
AppBar.Action(
title = stringResource(R.string.manga_download),
title = localize(MR.strings.manga_download),
icon = Icons.Outlined.Download,
onClick = { downloadExpanded = !downloadExpanded },
),
@ -118,7 +118,7 @@ fun MangaToolbar(
}
add(
AppBar.Action(
title = stringResource(R.string.action_filter),
title = localize(MR.strings.action_filter),
icon = Icons.Outlined.FilterList,
iconTint = filterTint,
onClick = onClickFilter,
@ -126,14 +126,14 @@ fun MangaToolbar(
)
add(
AppBar.OverflowAction(
title = stringResource(R.string.action_webview_refresh),
title = localize(MR.strings.action_webview_refresh),
onClick = onClickRefresh,
),
)
if (onClickEditCategory != null) {
add(
AppBar.OverflowAction(
title = stringResource(R.string.action_edit_categories),
title = localize(MR.strings.action_edit_categories),
onClick = onClickEditCategory,
),
)
@ -141,7 +141,7 @@ fun MangaToolbar(
if (onClickMigrate != null) {
add(
AppBar.OverflowAction(
title = stringResource(R.string.action_migrate),
title = localize(MR.strings.action_migrate),
onClick = onClickMigrate,
),
)
@ -149,7 +149,7 @@ fun MangaToolbar(
if (onClickShare != null) {
add(
AppBar.OverflowAction(
title = stringResource(R.string.action_share),
title = localize(MR.strings.action_share),
onClick = onClickShare,
),
)

View File

@ -10,11 +10,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localizePlural
import tachiyomi.presentation.core.util.secondaryItemAlpha
@Composable
@ -34,7 +34,7 @@ fun MissingChapterCountListItem(
) {
HorizontalDivider(modifier = Modifier.weight(1f))
Text(
text = pluralStringResource(id = R.plurals.missing_chapters, count = count, count),
text = localizePlural(MR.plurals.missing_chapters, count = count, count),
style = MaterialTheme.typography.labelMedium,
)
HorizontalDivider(modifier = Modifier.weight(1f))

View File

@ -27,12 +27,12 @@ import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.TextButton
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrolledToStart
@ -49,10 +49,10 @@ fun ScanlatorFilterDialog(
val mutableExcludedScanlators = remember(excludedScanlators) { excludedScanlators.toMutableStateList() }
AlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(text = stringResource(R.string.exclude_scanlators)) },
title = { Text(text = localize(MR.strings.exclude_scanlators)) },
text = textFunc@{
if (sortedAvailableScanlators.isEmpty()) {
Text(text = stringResource(R.string.no_scanlators_found))
Text(text = localize(MR.strings.no_scanlators_found))
return@textFunc
}
Box {
@ -108,16 +108,16 @@ fun ScanlatorFilterDialog(
confirmButton = {
if (sortedAvailableScanlators.isEmpty()) {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
} else {
FlowRow {
TextButton(onClick = mutableExcludedScanlators::clear) {
Text(text = stringResource(R.string.action_reset))
Text(text = localize(MR.strings.action_reset))
}
Spacer(modifier = Modifier.weight(1f))
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
TextButton(
onClick = {
@ -125,7 +125,7 @@ fun ScanlatorFilterDialog(
onDismissRequest()
},
) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
}
}

View File

@ -14,7 +14,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.halilibo.richtext.markdown.Markdown
@ -22,8 +21,9 @@ import com.halilibo.richtext.ui.RichTextStyle
import com.halilibo.richtext.ui.material3.Material3RichText
import com.halilibo.richtext.ui.string.RichTextStringStyle
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.InfoScreen
@Composable
@ -36,11 +36,11 @@ fun NewUpdateScreen(
) {
InfoScreen(
icon = Icons.Outlined.NewReleases,
headingText = stringResource(R.string.update_check_notification_update_available),
headingText = localize(MR.strings.update_check_notification_update_available),
subtitleText = versionName,
acceptText = stringResource(R.string.update_check_confirm),
acceptText = localize(MR.strings.update_check_confirm),
onAcceptClick = onAcceptUpdate,
rejectText = stringResource(R.string.action_not_now),
rejectText = localize(MR.strings.action_not_now),
onRejectClick = onRejectUpdate,
) {
Material3RichText(
@ -59,7 +59,7 @@ fun NewUpdateScreen(
onClick = onOpenInBrowser,
modifier = Modifier.padding(top = MaterialTheme.padding.small),
) {
Text(text = stringResource(R.string.update_check_open))
Text(text = localize(MR.strings.update_check_open))
Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny))
Icon(imageVector = Icons.AutoMirrored.Outlined.OpenInNew, contentDescription = null)
}

View File

@ -3,9 +3,9 @@ package eu.kanade.presentation.more.settings
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.Tracker
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.core.preference.Preference as PreferenceData
sealed class Preference {
@ -112,7 +112,7 @@ sealed class Preference {
v.map { e[it] }
.takeIf { it.isNotEmpty() }
?.joinToString()
} ?: stringResource(R.string.none)
} ?: localize(MR.strings.none)
subtitle?.format(combined)
},
override val icon: ImageVector? = null,

View File

@ -1,15 +1,15 @@
package eu.kanade.presentation.more.settings
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.RowScope
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.StringResource
import eu.kanade.presentation.components.AppBar
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
@Composable
fun PreferenceScaffold(
@StringRes titleRes: Int,
titleRes: StringResource,
actions: @Composable RowScope.() -> Unit = {},
onBackPressed: (() -> Unit)? = null,
itemsProvider: @Composable () -> List<Preference>,
@ -17,7 +17,7 @@ fun PreferenceScaffold(
Scaffold(
topBar = {
AppBar(
title = stringResource(titleRes),
title = localize(titleRes),
navigateUp = onBackPressed,
actions = actions,
scrollBehavior = it,

View File

@ -3,10 +3,10 @@ package eu.kanade.presentation.more.settings.screen
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.category.visualName
import eu.kanade.tachiyomi.R
import tachiyomi.domain.category.model.Category
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
/**
* Returns a string of categories name for settings subtitle
@ -34,15 +34,15 @@ fun getCategoriesLabel(
includedCategories.isNotEmpty() && includedCategories.size != allCategories.size ->
includedCategories.joinToString { it.visualName(context) }
// All explicitly selected
includedCategories.size == allCategories.size -> stringResource(R.string.all)
allExcluded -> stringResource(R.string.none)
else -> stringResource(R.string.all)
includedCategories.size == allCategories.size -> localize(MR.strings.all)
allExcluded -> localize(MR.strings.none)
else -> localize(MR.strings.all)
}
val excludedItemsText = when {
excludedCategories.isEmpty() -> stringResource(R.string.none)
allExcluded -> stringResource(R.string.all)
excludedCategories.isEmpty() -> localize(MR.strings.none)
allExcluded -> localize(MR.strings.all)
else -> excludedCategories.joinToString { it.visualName(context) }
}
return stringResource(R.string.include, includedItemsText) + "\n" +
stringResource(R.string.exclude, excludedItemsText)
return localize(MR.strings.include, includedItemsText) + "\n" +
localize(MR.strings.exclude, excludedItemsText)
}

View File

@ -1,10 +1,10 @@
package eu.kanade.presentation.more.settings.screen
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.RowScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import cafe.adriel.voyager.core.screen.Screen
import dev.icerock.moko.resources.StringResource
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.PreferenceScaffold
import eu.kanade.presentation.util.LocalBackPress
@ -13,8 +13,7 @@ interface SearchableSettings : Screen {
@Composable
@ReadOnlyComposable
@StringRes
fun getTitleRes(): Int
fun getTitleRes(): StringResource
@Composable
fun getPreferences(): List<Preference>

View File

@ -3,7 +3,6 @@ package eu.kanade.presentation.more.settings.screen
import android.app.Activity
import android.content.Context
import android.os.Build
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -13,7 +12,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.core.app.ActivityCompat
import androidx.core.os.LocaleListCompat
import eu.kanade.domain.ui.UiPreferences
@ -29,6 +27,9 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.merge
import org.xmlpull.v1.XmlPullParser
import tachiyomi.core.i18n.localize
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -38,8 +39,7 @@ object SettingsAppearanceScreen : SearchableSettings {
@ReadOnlyComposable
@Composable
@StringRes
override fun getTitleRes() = R.string.pref_category_appearance
override fun getTitleRes() = MR.strings.pref_category_appearance
@Composable
override fun getPreferences(): List<Preference> {
@ -80,26 +80,26 @@ object SettingsAppearanceScreen : SearchableSettings {
}
return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_theme),
title = localize(MR.strings.pref_category_theme),
preferenceItems = listOf(
Preference.PreferenceItem.ListPreference(
pref = themeModePref,
title = stringResource(R.string.pref_theme_mode),
title = localize(MR.strings.pref_theme_mode),
entries = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mapOf(
ThemeMode.SYSTEM to stringResource(R.string.theme_system),
ThemeMode.LIGHT to stringResource(R.string.theme_light),
ThemeMode.DARK to stringResource(R.string.theme_dark),
ThemeMode.SYSTEM to localize(MR.strings.theme_system),
ThemeMode.LIGHT to localize(MR.strings.theme_light),
ThemeMode.DARK to localize(MR.strings.theme_dark),
)
} else {
mapOf(
ThemeMode.LIGHT to stringResource(R.string.theme_light),
ThemeMode.DARK to stringResource(R.string.theme_dark),
ThemeMode.LIGHT to localize(MR.strings.theme_light),
ThemeMode.DARK to localize(MR.strings.theme_dark),
)
},
),
Preference.PreferenceItem.CustomPreference(
title = stringResource(R.string.pref_app_theme),
title = localize(MR.strings.pref_app_theme),
) { item ->
val value by appThemePref.collectAsState()
AppThemePreferenceWidget(
@ -111,7 +111,7 @@ object SettingsAppearanceScreen : SearchableSettings {
},
Preference.PreferenceItem.SwitchPreference(
pref = amoledPref,
title = stringResource(R.string.pref_dark_theme_pure_black),
title = localize(MR.strings.pref_dark_theme_pure_black),
enabled = themeMode != ThemeMode.LIGHT,
),
),
@ -144,11 +144,11 @@ object SettingsAppearanceScreen : SearchableSettings {
}
return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_display),
title = localize(MR.strings.pref_category_display),
preferenceItems = listOf(
Preference.PreferenceItem.BasicListPreference(
value = currentLanguage,
title = stringResource(R.string.pref_app_language),
title = localize(MR.strings.pref_app_language),
entries = langs,
onValueChanged = { newValue ->
currentLanguage = newValue
@ -157,28 +157,28 @@ object SettingsAppearanceScreen : SearchableSettings {
),
Preference.PreferenceItem.ListPreference(
pref = uiPreferences.tabletUiMode(),
title = stringResource(R.string.pref_tablet_ui_mode),
entries = TabletUiMode.entries.associateWith { stringResource(it.titleResId) },
title = localize(MR.strings.pref_tablet_ui_mode),
entries = TabletUiMode.entries.associateWith { localize(it.titleRes) },
onValueChanged = {
context.toast(R.string.requires_app_restart)
context.toast(MR.strings.requires_app_restart)
true
},
),
Preference.PreferenceItem.ListPreference(
pref = uiPreferences.dateFormat(),
title = stringResource(R.string.pref_date_format),
title = localize(MR.strings.pref_date_format),
entries = DateFormats
.associateWith {
val formattedDate = UiPreferences.dateFormat(it).format(now)
"${it.ifEmpty { stringResource(R.string.label_default) }} ($formattedDate)"
"${it.ifEmpty { localize(MR.strings.label_default) }} ($formattedDate)"
},
),
Preference.PreferenceItem.SwitchPreference(
pref = uiPreferences.relativeTime(),
title = stringResource(R.string.pref_relative_format),
subtitle = stringResource(
R.string.pref_relative_format_summary,
stringResource(R.string.relative_time_today),
title = localize(MR.strings.pref_relative_format),
subtitle = localize(
MR.strings.pref_relative_format_summary,
localize(MR.strings.relative_time_today),
formattedNow,
),
),
@ -205,7 +205,7 @@ object SettingsAppearanceScreen : SearchableSettings {
}
langs.sortBy { it.second }
langs.add(0, Pair("", context.getString(R.string.label_default)))
langs.add(0, Pair("", context.localize(MR.strings.label_default)))
return langs.toMap()
}

View File

@ -8,7 +8,6 @@ import android.text.format.Formatter
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
@ -27,7 +26,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.more.settings.Preference
@ -36,7 +34,6 @@ import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
import eu.kanade.presentation.permissions.PermissionRequestHelper
import eu.kanade.presentation.util.relativeTimeSpanString
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupCreateJob
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
@ -47,11 +44,14 @@ import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.copyToClipboard
import eu.kanade.tachiyomi.util.system.toast
import logcat.LogPriority
import tachiyomi.core.i18n.localize
import tachiyomi.core.util.lang.launchNonCancellable
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -60,8 +60,7 @@ object SettingsDataScreen : SearchableSettings {
@ReadOnlyComposable
@Composable
@StringRes
override fun getTitleRes() = R.string.label_data_storage
override fun getTitleRes() = MR.strings.label_data_storage
@Composable
override fun getPreferences(): List<Preference> {
@ -83,7 +82,7 @@ object SettingsDataScreen : SearchableSettings {
val lastAutoBackup by backupPreferences.lastAutoBackupTimestamp().collectAsState()
return Preference.PreferenceGroup(
title = stringResource(R.string.label_backup),
title = localize(MR.strings.label_backup),
preferenceItems = listOf(
// Manual actions
getCreateBackupPref(),
@ -92,14 +91,14 @@ object SettingsDataScreen : SearchableSettings {
// Automatic backups
Preference.PreferenceItem.ListPreference(
pref = backupIntervalPref,
title = stringResource(R.string.pref_backup_interval),
title = localize(MR.strings.pref_backup_interval),
entries = mapOf(
0 to stringResource(R.string.off),
6 to stringResource(R.string.update_6hour),
12 to stringResource(R.string.update_12hour),
24 to stringResource(R.string.update_24hour),
48 to stringResource(R.string.update_48hour),
168 to stringResource(R.string.update_weekly),
0 to localize(MR.strings.off),
6 to localize(MR.strings.update_6hour),
12 to localize(MR.strings.update_12hour),
24 to localize(MR.strings.update_24hour),
48 to localize(MR.strings.update_48hour),
168 to localize(MR.strings.update_weekly),
),
onValueChanged = {
BackupCreateJob.setupTask(context, it)
@ -109,12 +108,12 @@ object SettingsDataScreen : SearchableSettings {
Preference.PreferenceItem.ListPreference(
pref = backupPreferences.numberOfBackups(),
enabled = backupInterval != 0,
title = stringResource(R.string.pref_backup_slots),
title = localize(MR.strings.pref_backup_slots),
entries = listOf(2, 3, 4, 5).associateWith { it.toString() },
),
Preference.PreferenceItem.InfoPreference(
stringResource(R.string.backup_info) + "\n\n" +
stringResource(R.string.last_auto_backup_info, relativeTimeSpanString(lastAutoBackup)),
localize(MR.strings.backup_info) + "\n\n" +
localize(MR.strings.last_auto_backup_info, relativeTimeSpanString(lastAutoBackup)),
),
),
)
@ -124,8 +123,8 @@ object SettingsDataScreen : SearchableSettings {
private fun getCreateBackupPref(): Preference.PreferenceItem.TextPreference {
val navigator = LocalNavigator.currentOrThrow
return Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_create_backup),
subtitle = stringResource(R.string.pref_create_backup_summ),
title = localize(MR.strings.pref_create_backup),
subtitle = localize(MR.strings.pref_create_backup_summ),
onClick = { navigator.push(CreateBackupScreen()) },
)
}
@ -140,7 +139,7 @@ object SettingsDataScreen : SearchableSettings {
is InvalidRestore -> {
AlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(text = stringResource(R.string.invalid_backup_file)) },
title = { Text(text = localize(MR.strings.invalid_backup_file)) },
text = { Text(text = listOfNotNull(err.uri, err.message).joinToString("\n\n")) },
dismissButton = {
TextButton(
@ -149,12 +148,12 @@ object SettingsDataScreen : SearchableSettings {
onDismissRequest()
},
) {
Text(text = stringResource(R.string.action_copy_to_clipboard))
Text(text = localize(MR.strings.action_copy_to_clipboard))
}
},
confirmButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
)
@ -162,15 +161,15 @@ object SettingsDataScreen : SearchableSettings {
is MissingRestoreComponents -> {
AlertDialog(
onDismissRequest = onDismissRequest,
title = { Text(text = stringResource(R.string.pref_restore_backup)) },
title = { Text(text = localize(MR.strings.pref_restore_backup)) },
text = {
Column(
modifier = Modifier.verticalScroll(rememberScrollState()),
) {
val msg = buildString {
append(stringResource(R.string.backup_restore_content_full))
append(localize(MR.strings.backup_restore_content_full))
if (err.sources.isNotEmpty()) {
append("\n\n").append(stringResource(R.string.backup_restore_missing_sources))
append("\n\n").append(localize(MR.strings.backup_restore_missing_sources))
err.sources.joinTo(
this,
separator = "\n- ",
@ -178,7 +177,7 @@ object SettingsDataScreen : SearchableSettings {
)
}
if (err.trackers.isNotEmpty()) {
append("\n\n").append(stringResource(R.string.backup_restore_missing_trackers))
append("\n\n").append(localize(MR.strings.backup_restore_missing_trackers))
err.trackers.joinTo(
this,
separator = "\n- ",
@ -196,7 +195,7 @@ object SettingsDataScreen : SearchableSettings {
onDismissRequest()
},
) {
Text(text = stringResource(R.string.action_restore))
Text(text = localize(MR.strings.action_restore))
}
},
)
@ -209,12 +208,12 @@ object SettingsDataScreen : SearchableSettings {
object : ActivityResultContracts.GetContent() {
override fun createIntent(context: Context, input: String): Intent {
val intent = super.createIntent(context, input)
return Intent.createChooser(intent, context.getString(R.string.file_select_backup))
return Intent.createChooser(intent, context.localize(MR.strings.file_select_backup))
}
},
) {
if (it == null) {
context.toast(R.string.file_null_uri_error)
context.toast(MR.strings.file_null_uri_error)
return@rememberLauncherForActivityResult
}
@ -234,17 +233,17 @@ object SettingsDataScreen : SearchableSettings {
}
return Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_restore_backup),
subtitle = stringResource(R.string.pref_restore_backup_summ),
title = localize(MR.strings.pref_restore_backup),
subtitle = localize(MR.strings.pref_restore_backup_summ),
onClick = {
if (!BackupRestoreJob.isRunning(context)) {
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
context.toast(MR.strings.restore_miui_warning, Toast.LENGTH_LONG)
}
// no need to catch because it's wrapped with a chooser
chooseBackup.launch("*/*")
} else {
context.toast(R.string.restore_in_progress)
context.toast(MR.strings.restore_in_progress)
}
},
)
@ -267,24 +266,24 @@ object SettingsDataScreen : SearchableSettings {
// SY <--
return Preference.PreferenceGroup(
title = stringResource(R.string.label_data),
title = localize(MR.strings.label_data),
preferenceItems = listOf(
getStorageInfoPref(cacheReadableSize),
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.pref_clear_chapter_cache),
subtitle = stringResource(R.string.used_cache, cacheReadableSize),
title = localize(MR.strings.pref_clear_chapter_cache),
subtitle = localize(MR.strings.used_cache, cacheReadableSize),
onClick = {
scope.launchNonCancellable {
try {
val deletedFiles = chapterCache.clear()
withUIContext {
context.toast(context.getString(R.string.cache_deleted, deletedFiles))
context.toast(context.localize(MR.strings.cache_deleted, deletedFiles))
cacheReadableSizeSema++
}
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e)
withUIContext { context.toast(R.string.cache_delete_error) }
withUIContext { context.toast(MR.strings.cache_delete_error) }
}
}
},
@ -311,7 +310,7 @@ object SettingsDataScreen : SearchableSettings {
// SY <--
Preference.PreferenceItem.SwitchPreference(
pref = libraryPreferences.autoClearChapterCache(),
title = stringResource(R.string.pref_auto_clear_chapter_cache),
title = localize(MR.strings.pref_auto_clear_chapter_cache),
),
),
)
@ -330,10 +329,10 @@ object SettingsDataScreen : SearchableSettings {
}
return Preference.PreferenceItem.CustomPreference(
title = stringResource(R.string.pref_storage_usage),
title = localize(MR.strings.pref_storage_usage),
) {
BasePreferenceWidget(
title = stringResource(R.string.pref_storage_usage),
title = localize(MR.strings.pref_storage_usage),
subcomponent = {
// TODO: downloads, SD cards, bar representation?, i18n
Box(modifier = Modifier.padding(horizontal = PrefsHorizontalPadding)) {

View File

@ -4,7 +4,6 @@ import android.content.Intent
import android.os.Environment
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.collectAsState
@ -14,19 +13,19 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.util.fastMap
import androidx.core.net.toUri
import com.hippo.unifile.UniFile
import eu.kanade.presentation.category.visualName
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.widget.TriStateListDialog
import eu.kanade.tachiyomi.R
import kotlinx.coroutines.runBlocking
import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category
import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.i18n.localizePlural
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -36,8 +35,7 @@ object SettingsDownloadScreen : SearchableSettings {
@ReadOnlyComposable
@Composable
@StringRes
override fun getTitleRes() = R.string.pref_category_downloads
override fun getTitleRes() = MR.strings.pref_category_downloads
@Composable
override fun getPreferences(): List<Preference> {
@ -49,16 +47,16 @@ object SettingsDownloadScreen : SearchableSettings {
getDownloadLocationPreference(downloadPreferences = downloadPreferences),
Preference.PreferenceItem.SwitchPreference(
pref = downloadPreferences.downloadOnlyOverWifi(),
title = stringResource(R.string.connected_to_wifi),
title = localize(MR.strings.connected_to_wifi),
),
Preference.PreferenceItem.SwitchPreference(
pref = downloadPreferences.saveChaptersAsCBZ(),
title = stringResource(R.string.save_chapter_as_cbz),
title = localize(MR.strings.save_chapter_as_cbz),
),
Preference.PreferenceItem.SwitchPreference(
pref = downloadPreferences.splitTallImages(),
title = stringResource(R.string.split_tall_images),
subtitle = stringResource(R.string.split_tall_images_summary),
title = localize(MR.strings.split_tall_images),
subtitle = localize(MR.strings.split_tall_images_summary),
),
getDeleteChaptersGroup(
downloadPreferences = downloadPreferences,
@ -99,15 +97,15 @@ object SettingsDownloadScreen : SearchableSettings {
return Preference.PreferenceItem.ListPreference(
pref = currentDirPref,
title = stringResource(R.string.pref_download_directory),
title = localize(MR.strings.pref_download_directory),
subtitleProvider = { value, _ ->
remember(value) {
UniFile.fromUri(context, value.toUri())?.filePath
} ?: stringResource(R.string.invalid_location, value)
} ?: localize(MR.strings.invalid_location, value)
},
entries = mapOf(
defaultDirPair,
customDirEntryKey to stringResource(R.string.custom_dir),
customDirEntryKey to localize(MR.strings.custom_dir),
),
onValueChanged = {
val default = it == defaultDirPair.first
@ -121,7 +119,7 @@ object SettingsDownloadScreen : SearchableSettings {
@Composable
private fun rememberDefaultDownloadDir(): Pair<String, String> {
val appName = stringResource(R.string.app_name)
val appName = localize(MR.strings.app_name)
return remember {
val file = UniFile.fromFile(
File(
@ -139,27 +137,27 @@ object SettingsDownloadScreen : SearchableSettings {
categories: List<Category>,
): Preference.PreferenceGroup {
return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_delete_chapters),
title = localize(MR.strings.pref_category_delete_chapters),
preferenceItems = listOf(
Preference.PreferenceItem.SwitchPreference(
pref = downloadPreferences.removeAfterMarkedAsRead(),
title = stringResource(R.string.pref_remove_after_marked_as_read),
title = localize(MR.strings.pref_remove_after_marked_as_read),
),
Preference.PreferenceItem.ListPreference(
pref = downloadPreferences.removeAfterReadSlots(),
title = stringResource(R.string.pref_remove_after_read),
title = localize(MR.strings.pref_remove_after_read),
entries = mapOf(
-1 to stringResource(R.string.disabled),
0 to stringResource(R.string.last_read_chapter),
1 to stringResource(R.string.second_to_last),
2 to stringResource(R.string.third_to_last),
3 to stringResource(R.string.fourth_to_last),
4 to stringResource(R.string.fifth_to_last),
-1 to localize(MR.strings.disabled),
0 to localize(MR.strings.last_read_chapter),
1 to localize(MR.strings.second_to_last),
2 to localize(MR.strings.third_to_last),
3 to localize(MR.strings.fourth_to_last),
4 to localize(MR.strings.fifth_to_last),
),
),
Preference.PreferenceItem.SwitchPreference(
pref = downloadPreferences.removeBookmarkedChapters(),
title = stringResource(R.string.pref_remove_bookmarked_chapters),
title = localize(MR.strings.pref_remove_bookmarked_chapters),
),
getExcludedCategoriesPreference(
downloadPreferences = downloadPreferences,
@ -176,7 +174,7 @@ object SettingsDownloadScreen : SearchableSettings {
): Preference.PreferenceItem.MultiSelectListPreference {
return Preference.PreferenceItem.MultiSelectListPreference(
pref = downloadPreferences.removeExcludeCategories(),
title = stringResource(R.string.pref_remove_exclude_categories),
title = localize(MR.strings.pref_remove_exclude_categories),
entries = categories().associate { it.id.toString() to it.visualName },
)
}
@ -197,8 +195,8 @@ object SettingsDownloadScreen : SearchableSettings {
var showDialog by rememberSaveable { mutableStateOf(false) }
if (showDialog) {
TriStateListDialog(
title = stringResource(R.string.categories),
message = stringResource(R.string.pref_download_new_categories_details),
title = localize(MR.strings.categories),
message = localize(MR.strings.pref_download_new_categories_details),
items = allCategories,
initialChecked = included.mapNotNull { id -> allCategories.find { it.id.toString() == id } },
initialInversed = excluded.mapNotNull { id -> allCategories.find { it.id.toString() == id } },
@ -213,14 +211,14 @@ object SettingsDownloadScreen : SearchableSettings {
}
return Preference.PreferenceGroup(
title = stringResource(R.string.pref_category_auto_download),
title = localize(MR.strings.pref_category_auto_download),
preferenceItems = listOf(
Preference.PreferenceItem.SwitchPreference(
pref = downloadNewChaptersPref,
title = stringResource(R.string.pref_download_new),
title = localize(MR.strings.pref_download_new),
),
Preference.PreferenceItem.TextPreference(
title = stringResource(R.string.categories),
title = localize(MR.strings.categories),
subtitle = getCategoriesLabel(
allCategories = allCategories,
included = included,
@ -238,20 +236,20 @@ object SettingsDownloadScreen : SearchableSettings {
downloadPreferences: DownloadPreferences,
): Preference.PreferenceGroup {
return Preference.PreferenceGroup(
title = stringResource(R.string.download_ahead),
title = localize(MR.strings.download_ahead),
preferenceItems = listOf(
Preference.PreferenceItem.ListPreference(
pref = downloadPreferences.autoDownloadWhileReading(),
title = stringResource(R.string.auto_download_while_reading),
title = localize(MR.strings.auto_download_while_reading),
entries = listOf(0, 2, 3, 5, 10).associateWith {
if (it == 0) {
stringResource(R.string.disabled)
localize(MR.strings.disabled)
} else {
pluralStringResource(id = R.plurals.next_unread_chapters, count = it, it)
localizePlural(MR.plurals.next_unread_chapters, count = it, it)
}
},
),
Preference.PreferenceItem.InfoPreference(stringResource(R.string.download_ahead_info)),
Preference.PreferenceItem.InfoPreference(localize(MR.strings.download_ahead_info)),
),
)
}

View File

@ -41,7 +41,6 @@ import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
@ -53,8 +52,9 @@ import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.components.UpIcon
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
import cafe.adriel.voyager.core.screen.Screen as VoyagerScreen
@ -118,7 +118,7 @@ class SettingsSearchScreen : Screen() {
decorationBox = {
if (textFieldValue.text.isEmpty()) {
Text(
text = stringResource(R.string.action_search_settings),
text = localize(MR.strings.action_search_settings),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyLarge,
)
@ -215,7 +215,7 @@ private fun SearchResult(
when {
it == null -> {}
it.isEmpty() -> {
EmptyScreen(stringResource(R.string.no_results_found))
EmptyScreen(localize(MR.strings.no_results_found))
}
else -> {
LazyColumn(
@ -264,7 +264,7 @@ private fun getIndex() = settingScreens
// SY <--
.map { screen ->
SettingsData(
title = stringResource(screen.getTitleRes()),
title = localize(screen.getTitleRes()),
route = screen,
contents = screen.getPreferences(),
)

View File

@ -1,7 +1,6 @@
package eu.kanade.presentation.more.settings.screen
import android.content.Context
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@ -13,7 +12,6 @@ import androidx.compose.material.icons.automirrored.outlined.HelpOutline
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.HelpOutline
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
@ -34,7 +32,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
@ -42,9 +39,9 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.EnhancedTracker
import eu.kanade.tachiyomi.data.track.Tracker
import eu.kanade.tachiyomi.data.track.TrackerManager
@ -57,7 +54,9 @@ import eu.kanade.tachiyomi.util.system.toast
import tachiyomi.core.util.lang.launchIO
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -65,8 +64,7 @@ object SettingsTrackingScreen : SearchableSettings {
@ReadOnlyComposable
@Composable
@StringRes
override fun getTitleRes() = R.string.pref_category_tracking
override fun getTitleRes() = MR.strings.pref_category_tracking
@Composable
override fun RowScope.AppBarAction() {
@ -74,7 +72,7 @@ object SettingsTrackingScreen : SearchableSettings {
IconButton(onClick = { uriHandler.openUri("https://tachiyomi.org/docs/guides/tracking") }) {
Icon(
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
contentDescription = stringResource(R.string.tracking_guide),
contentDescription = localize(MR.strings.tracking_guide),
)
}
}
@ -111,10 +109,10 @@ object SettingsTrackingScreen : SearchableSettings {
val acceptedSources = (service as EnhancedTracker).getAcceptedSources()
sourceManager.getCatalogueSources().any { it::class.qualifiedName in acceptedSources }
}
var enhancedTrackerInfo = stringResource(R.string.enhanced_tracking_info)
var enhancedTrackerInfo = localize(MR.strings.enhanced_tracking_info)
if (enhancedTrackers.second.isNotEmpty()) {
val missingSourcesInfo = stringResource(
R.string.enhanced_services_not_installed,
val missingSourcesInfo = localize(
MR.strings.enhanced_services_not_installed,
enhancedTrackers.second.joinToString { it.name },
)
enhancedTrackerInfo += "\n\n$missingSourcesInfo"
@ -123,10 +121,10 @@ object SettingsTrackingScreen : SearchableSettings {
return listOf(
Preference.PreferenceItem.SwitchPreference(
pref = trackPreferences.autoUpdateTrack(),
title = stringResource(R.string.pref_auto_update_manga_sync),
title = localize(MR.strings.pref_auto_update_manga_sync),
),
Preference.PreferenceGroup(
title = stringResource(R.string.services),
title = localize(MR.strings.services),
preferenceItems = listOf(
Preference.PreferenceItem.TrackerPreference(
title = trackerManager.myAnimeList.name,
@ -143,13 +141,13 @@ object SettingsTrackingScreen : SearchableSettings {
Preference.PreferenceItem.TrackerPreference(
title = trackerManager.kitsu.name,
tracker = trackerManager.kitsu,
login = { dialog = LoginDialog(trackerManager.kitsu, R.string.email) },
login = { dialog = LoginDialog(trackerManager.kitsu, MR.strings.email) },
logout = { dialog = LogoutDialog(trackerManager.kitsu) },
),
Preference.PreferenceItem.TrackerPreference(
title = trackerManager.mangaUpdates.name,
tracker = trackerManager.mangaUpdates,
login = { dialog = LoginDialog(trackerManager.mangaUpdates, R.string.username) },
login = { dialog = LoginDialog(trackerManager.mangaUpdates, MR.strings.username) },
logout = { dialog = LogoutDialog(trackerManager.mangaUpdates) },
),
Preference.PreferenceItem.TrackerPreference(
@ -164,11 +162,11 @@ object SettingsTrackingScreen : SearchableSettings {
login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) },
logout = { dialog = LogoutDialog(trackerManager.bangumi) },
),
Preference.PreferenceItem.InfoPreference(stringResource(R.string.tracking_info)),
Preference.PreferenceItem.InfoPreference(localize(MR.strings.tracking_info)),
),
),
Preference.PreferenceGroup(
title = stringResource(R.string.enhanced_services),
title = localize(MR.strings.enhanced_services),
preferenceItems = enhancedTrackers.first
.map { service ->
Preference.PreferenceItem.TrackerPreference(
@ -185,7 +183,7 @@ object SettingsTrackingScreen : SearchableSettings {
@Composable
private fun TrackingLoginDialog(
tracker: Tracker,
@StringRes uNameStringRes: Int,
uNameStringRes: StringResource,
onDismissRequest: () -> Unit,
) {
val context = LocalContext.current
@ -201,13 +199,13 @@ object SettingsTrackingScreen : SearchableSettings {
title = {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = stringResource(R.string.login_title, tracker.name),
text = localize(MR.strings.login_title, tracker.name),
modifier = Modifier.weight(1f),
)
IconButton(onClick = onDismissRequest) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = stringResource(R.string.action_close),
contentDescription = localize(MR.strings.action_close),
)
}
}
@ -218,7 +216,7 @@ object SettingsTrackingScreen : SearchableSettings {
modifier = Modifier.fillMaxWidth(),
value = username,
onValueChange = { username = it },
label = { Text(text = stringResource(uNameStringRes)) },
label = { Text(text = localize(uNameStringRes)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
singleLine = true,
isError = inputError && !processing,
@ -229,7 +227,7 @@ object SettingsTrackingScreen : SearchableSettings {
modifier = Modifier.fillMaxWidth(),
value = password,
onValueChange = { password = it },
label = { Text(text = stringResource(R.string.password)) },
label = { Text(text = localize(MR.strings.password)) },
trailingIcon = {
IconButton(onClick = { hidePassword = !hidePassword }) {
Icon(
@ -275,8 +273,8 @@ object SettingsTrackingScreen : SearchableSettings {
}
},
) {
val id = if (processing) R.string.loading else R.string.login
Text(text = stringResource(id))
val id = if (processing) MR.strings.loading else MR.strings.login
Text(text = localize(id))
}
},
)
@ -290,7 +288,7 @@ object SettingsTrackingScreen : SearchableSettings {
): Boolean {
return try {
tracker.login(username, password)
withUIContext { context.toast(R.string.login_success) }
withUIContext { context.toast(MR.strings.login_success) }
true
} catch (e: Throwable) {
tracker.logout()
@ -309,7 +307,7 @@ object SettingsTrackingScreen : SearchableSettings {
onDismissRequest = onDismissRequest,
title = {
Text(
text = stringResource(R.string.logout_title, tracker.name),
text = localize(MR.strings.logout_title, tracker.name),
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth(),
)
@ -320,21 +318,21 @@ object SettingsTrackingScreen : SearchableSettings {
modifier = Modifier.weight(1f),
onClick = onDismissRequest,
) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
Button(
modifier = Modifier.weight(1f),
onClick = {
tracker.logout()
onDismissRequest()
context.toast(R.string.logout_success)
context.toast(MR.strings.logout_success)
},
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.error,
contentColor = MaterialTheme.colorScheme.onError,
),
) {
Text(text = stringResource(R.string.logout))
Text(text = localize(MR.strings.logout))
}
}
},
@ -344,7 +342,7 @@ object SettingsTrackingScreen : SearchableSettings {
private data class LoginDialog(
val tracker: Tracker,
@StringRes val uNameStringRes: Int,
val uNameStringRes: StringResource,
)
private data class LogoutDialog(

View File

@ -19,7 +19,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
@ -30,7 +29,6 @@ import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
import eu.kanade.presentation.util.LocalBackPress
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
import eu.kanade.tachiyomi.ui.more.NewUpdateScreen
import eu.kanade.tachiyomi.util.CrashLogUtil
@ -45,9 +43,11 @@ import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.release.interactor.GetApplicationRelease
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.LinkIcon
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.icons.CustomIcons
import tachiyomi.presentation.core.icons.Discord
import tachiyomi.presentation.core.icons.Facebook
@ -79,7 +79,7 @@ object AboutScreen : Screen() {
Scaffold(
topBar = { scrollBehavior ->
AppBar(
title = stringResource(R.string.pref_category_about),
title = localize(MR.strings.pref_category_about),
navigateUp = if (handleBack != null) handleBack::invoke else null,
scrollBehavior = scrollBehavior,
)
@ -94,7 +94,7 @@ object AboutScreen : Screen() {
item {
TextPreferenceWidget(
title = stringResource(R.string.version),
title = localize(MR.strings.version),
subtitle = getVersionName(withBuildDate = true),
onPreferenceClick = {
val deviceInfo = CrashLogUtil(context).getDebugInfo()
@ -106,7 +106,7 @@ object AboutScreen : Screen() {
if (BuildConfig.INCLUDE_UPDATER) {
item {
TextPreferenceWidget(
title = stringResource(R.string.check_for_updates),
title = localize(MR.strings.check_for_updates),
widget = {
AnimatedVisibility(visible = isCheckingUpdates) {
CircularProgressIndicator(
@ -145,7 +145,7 @@ object AboutScreen : Screen() {
if (!BuildConfig.DEBUG) {
item {
TextPreferenceWidget(
title = stringResource(R.string.whats_new),
title = localize(MR.string.whats_new),
// SY -->
onPreferenceClick = { showWhatsNewDialog = true },
// SY <--
@ -155,21 +155,21 @@ object AboutScreen : Screen() {
item {
TextPreferenceWidget(
title = stringResource(R.string.help_translate),
title = localize(MR.strings.help_translate),
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/docs/contribute#translation") },
)
}
item {
TextPreferenceWidget(
title = stringResource(R.string.licenses),
title = localize(MR.strings.licenses),
onPreferenceClick = { navigator.push(OpenSourceLicensesScreen()) },
)
}
item {
TextPreferenceWidget(
title = stringResource(R.string.privacy_policy),
title = localize(MR.strings.privacy_policy),
onPreferenceClick = { uriHandler.openUri("https://tachiyomi.org/privacy/") },
)
}
@ -182,7 +182,7 @@ object AboutScreen : Screen() {
horizontalArrangement = Arrangement.Center,
) {
LinkIcon(
label = stringResource(R.string.website),
label = localize(MR.strings.website),
icon = Icons.Outlined.Public,
url = "https://tachiyomi.org",
)
@ -241,10 +241,10 @@ object AboutScreen : Screen() {
onAvailableUpdate(result)
}
is GetApplicationRelease.Result.NoNewUpdate -> {
context.toast(R.string.update_check_no_new_updates)
context.toast(MR.strings.update_check_no_new_updates)
}
is GetApplicationRelease.Result.OsTooOld -> {
context.toast(R.string.update_check_eol)
context.toast(MR.strings.update_check_eol)
}
else -> {}
}

View File

@ -9,7 +9,6 @@ import androidx.compose.material.icons.filled.Public
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.text.HtmlCompat
@ -19,9 +18,10 @@ import com.google.android.material.textview.MaterialTextView
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
class OpenSourceLibraryLicenseScreen(
private val name: String,
@ -44,7 +44,7 @@ class OpenSourceLibraryLicenseScreen(
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.website),
title = localize(MR.strings.website),
icon = Icons.Default.Public,
onClick = { uriHandler.openUri(website) },
),

View File

@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer
@ -12,8 +11,9 @@ import com.mikepenz.aboutlibraries.ui.compose.LibraryDefaults
import com.mikepenz.aboutlibraries.ui.compose.util.htmlReadyLicenseContent
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
class OpenSourceLicensesScreen : Screen() {
@ -23,7 +23,7 @@ class OpenSourceLicensesScreen : Screen() {
Scaffold(
topBar = { scrollBehavior ->
AppBar(
title = stringResource(R.string.licenses),
title = localize(MR.strings.licenses),
navigateUp = navigator::pop,
scrollBehavior = scrollBehavior,
)

View File

@ -10,7 +10,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.navigator.LocalNavigator
@ -18,12 +17,13 @@ import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.util.system.copyToClipboard
import kotlinx.collections.immutable.persistentListOf
import kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
class BackupSchemaScreen : Screen() {
@ -47,7 +47,7 @@ class BackupSchemaScreen : Screen() {
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_copy_to_clipboard),
title = localize(MR.strings.action_copy_to_clipboard),
icon = Icons.Default.ContentCopy,
onClick = {
context.copyToClipboard(title, schema)

View File

@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.WebViewUtil
import kotlinx.coroutines.guava.await
import tachiyomi.i18n.MR
class DebugInfoScreen : Screen() {
@ -24,7 +25,7 @@ class DebugInfoScreen : Screen() {
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
PreferenceScaffold(
titleRes = R.string.pref_debug_info,
titleRes = MR.strings.pref_debug_info,
onBackPressed = navigator::pop,
itemsProvider = {
listOf(

View File

@ -15,7 +15,6 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
@ -30,14 +29,15 @@ import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.util.Screen
import eu.kanade.presentation.util.ioCoroutineScope
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.copyToClipboard
import eu.kanade.tachiyomi.util.system.workManager
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.plus
class WorkerInfoScreen : Screen() {
@ -65,7 +65,7 @@ class WorkerInfoScreen : Screen() {
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_copy_to_clipboard),
title = localize(MR.strings.action_copy_to_clipboard),
icon = Icons.Default.ContentCopy,
onClick = {
context.copyToClipboard(title, enqueued + finished + running)

View File

@ -36,17 +36,17 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import eu.kanade.domain.ui.model.AppTheme
import eu.kanade.presentation.manga.components.MangaCover
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.isDynamicColorAvailable
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.secondaryItemAlpha
@Composable
@ -76,7 +76,7 @@ private fun AppThemesList(
) {
val appThemes = remember {
AppTheme.entries
.filterNot { it.titleResId == null || (it == AppTheme.MONET && !DeviceUtil.isDynamicColorAvailable) }
.filterNot { it.titleRes == null || (it == AppTheme.MONET && !DeviceUtil.isDynamicColorAvailable) }
}
LazyRow(
contentPadding = PaddingValues(horizontal = PrefsHorizontalPadding),
@ -104,7 +104,7 @@ private fun AppThemesList(
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(appTheme.titleResId!!),
text = localize(appTheme.titleRes!!),
modifier = Modifier
.fillMaxWidth()
.secondaryItemAlpha(),
@ -167,7 +167,7 @@ fun AppThemePreviewItem(
if (selected) {
Icon(
imageVector = Icons.Filled.CheckCircle,
contentDescription = stringResource(R.string.selected),
contentDescription = localize(MR.strings.selected),
tint = MaterialTheme.colorScheme.primary,
)
}

View File

@ -19,11 +19,11 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.window.DialogProperties
import eu.kanade.tachiyomi.R
import kotlinx.coroutines.launch
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun EditTextPreferenceWidget(
@ -83,12 +83,12 @@ fun EditTextPreferenceWidget(
}
},
) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
)

View File

@ -11,11 +11,11 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.secondaryItemAlpha
@Composable
@ -45,7 +45,7 @@ internal fun InfoWidget(text: String) {
private fun InfoWidgetPreview() {
TachiyomiTheme {
Surface {
InfoWidget(text = stringResource(R.string.download_ahead_info))
InfoWidget(text = localize(MR.strings.download_ahead_info))
}
}
}

View File

@ -22,10 +22,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrolledToStart
@ -75,7 +75,7 @@ fun <T> ListPreferenceWidget(
},
confirmButton = {
TextButton(onClick = { isDialogShown = false }) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
)

View File

@ -10,11 +10,11 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.window.DialogProperties
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.LabeledCheckbox
import tachiyomi.presentation.core.i18n.localize
@Composable
fun MultiSelectListPreferenceWidget(
@ -70,12 +70,12 @@ fun MultiSelectListPreferenceWidget(
isDialogShown = false
},
) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
dismissButton = {
TextButton(onClick = { isDialogShown = false }) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
)

View File

@ -15,12 +15,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.more.settings.LocalPreferenceHighlighted
import eu.kanade.presentation.track.components.TrackLogoIcon
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.Tracker
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun TrackingPreferenceWidget(
@ -55,7 +55,7 @@ fun TrackingPreferenceWidget(
.padding(4.dp)
.size(32.dp),
tint = Color(0xFF4CAF50),
contentDescription = stringResource(R.string.login_success),
contentDescription = localize(MR.strings.login_success),
)
}
}

View File

@ -27,9 +27,9 @@ import androidx.compose.runtime.toMutableStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrolledToStart
@ -102,11 +102,11 @@ fun <T> TriStateListDialog(
} else {
MaterialTheme.colorScheme.primary
},
contentDescription = stringResource(
contentDescription = localize(
when (state) {
State.UNCHECKED -> R.string.not_selected
State.CHECKED -> R.string.selected
State.INVERSED -> R.string.disabled
State.UNCHECKED -> MR.strings.not_selected
State.CHECKED -> MR.strings.selected
State.INVERSED -> MR.strings.disabled
},
),
)
@ -130,7 +130,7 @@ fun <T> TriStateListDialog(
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
confirmButton = {
@ -145,7 +145,7 @@ fun <T> TriStateListDialog(
onValueChanged(included, excluded)
},
) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
)

View File

@ -13,14 +13,14 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.more.stats.components.StatsItem
import eu.kanade.presentation.more.stats.components.StatsOverviewItem
import eu.kanade.presentation.more.stats.components.StatsSection
import eu.kanade.presentation.more.stats.data.StatsData
import eu.kanade.presentation.util.toDurationString
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import java.util.Locale
import kotlin.time.DurationUnit
import kotlin.time.toDuration
@ -55,28 +55,28 @@ fun StatsScreenContent(
private fun OverviewSection(
data: StatsData.Overview,
) {
val none = stringResource(R.string.none)
val none = localize(MR.strings.none)
val context = LocalContext.current
val readDurationString = remember(data.totalReadDuration) {
data.totalReadDuration
.toDuration(DurationUnit.MILLISECONDS)
.toDurationString(context, fallback = none)
}
StatsSection(R.string.label_overview_section) {
StatsSection(MR.strings.label_overview_section) {
Row {
StatsOverviewItem(
title = data.libraryMangaCount.toString(),
subtitle = stringResource(R.string.in_library),
subtitle = localize(MR.strings.in_library),
icon = Icons.Outlined.CollectionsBookmark,
)
StatsOverviewItem(
title = data.completedMangaCount.toString(),
subtitle = stringResource(R.string.label_completed_titles),
subtitle = localize(MR.strings.label_completed_titles),
icon = Icons.Outlined.LocalLibrary,
)
StatsOverviewItem(
title = readDurationString,
subtitle = stringResource(R.string.label_read_duration),
subtitle = localize(MR.strings.label_read_duration),
icon = Icons.Outlined.Schedule,
)
}
@ -87,19 +87,19 @@ private fun OverviewSection(
private fun TitlesStats(
data: StatsData.Titles,
) {
StatsSection(R.string.label_titles_section) {
StatsSection(MR.strings.label_titles_section) {
Row {
StatsItem(
data.globalUpdateItemCount.toString(),
stringResource(R.string.label_titles_in_global_update),
localize(MR.strings.label_titles_in_global_update),
)
StatsItem(
data.startedMangaCount.toString(),
stringResource(R.string.label_started),
localize(MR.strings.label_started),
)
StatsItem(
data.localMangaCount.toString(),
stringResource(R.string.label_local),
localize(MR.strings.label_local),
)
}
}
@ -109,19 +109,19 @@ private fun TitlesStats(
private fun ChapterStats(
data: StatsData.Chapters,
) {
StatsSection(R.string.chapters) {
StatsSection(MR.strings.chapters) {
Row {
StatsItem(
data.totalChapterCount.toString(),
stringResource(R.string.label_total_chapters),
localize(MR.strings.label_total_chapters),
)
StatsItem(
data.readChapterCount.toString(),
stringResource(R.string.label_read_chapters),
localize(MR.strings.label_read_chapters),
)
StatsItem(
data.downloadCount.toString(),
stringResource(R.string.label_downloaded),
localize(MR.strings.label_downloaded),
)
}
}
@ -131,7 +131,7 @@ private fun ChapterStats(
private fun TrackerStats(
data: StatsData.Trackers,
) {
val notApplicable = stringResource(R.string.not_applicable)
val notApplicable = localize(MR.strings.not_applicable)
val meanScoreStr = remember(data.trackedTitleCount, data.meanScore) {
if (data.trackedTitleCount > 0 && !data.meanScore.isNaN()) {
// All other numbers are localized in English
@ -140,19 +140,19 @@ private fun TrackerStats(
notApplicable
}
}
StatsSection(R.string.label_tracker_section) {
StatsSection(MR.strings.label_tracker_section) {
Row {
StatsItem(
data.trackedTitleCount.toString(),
stringResource(R.string.label_tracked_titles),
localize(MR.strings.label_tracked_titles),
)
StatsItem(
meanScoreStr,
stringResource(R.string.label_mean_score),
localize(MR.strings.label_mean_score),
)
StatsItem(
data.trackerCount.toString(),
stringResource(R.string.label_used),
localize(MR.strings.label_used),
)
}
}

View File

@ -1,6 +1,5 @@
package eu.kanade.presentation.more.stats.components
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
@ -9,17 +8,18 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.StringResource
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
@Composable
fun StatsSection(
@StringRes titleRes: Int,
titleRes: StringResource,
content: @Composable () -> Unit,
) {
Text(
modifier = Modifier.padding(horizontal = MaterialTheme.padding.extraLarge),
text = stringResource(titleRes),
text = localize(titleRes),
style = MaterialTheme.typography.titleSmall,
)
ElevatedCard(

View File

@ -26,8 +26,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.buildAnnotatedString
@ -36,13 +34,15 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
import tachiyomi.domain.chapter.service.calculateChapterGap
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.i18n.localizePlural
import tachiyomi.presentation.core.util.secondaryItemAlpha
@Composable
@ -58,25 +58,25 @@ fun ChapterTransition(
when (transition) {
is ChapterTransition.Prev -> {
TransitionText(
topLabel = stringResource(R.string.transition_previous),
topLabel = localize(MR.strings.transition_previous),
topChapter = goingToChapter,
topChapterDownloaded = goingToChapterDownloaded,
bottomLabel = stringResource(R.string.transition_current),
bottomLabel = localize(MR.strings.transition_current),
bottomChapter = currChapter,
bottomChapterDownloaded = currChapterDownloaded,
fallbackLabel = stringResource(R.string.transition_no_previous),
fallbackLabel = localize(MR.strings.transition_no_previous),
chapterGap = calculateChapterGap(currChapter.toDomainChapter(), goingToChapter?.toDomainChapter()),
)
}
is ChapterTransition.Next -> {
TransitionText(
topLabel = stringResource(R.string.transition_finished),
topLabel = localize(MR.strings.transition_finished),
topChapter = currChapter,
topChapterDownloaded = currChapterDownloaded,
bottomLabel = stringResource(R.string.transition_next),
bottomLabel = localize(MR.strings.transition_next),
bottomChapter = goingToChapter,
bottomChapterDownloaded = goingToChapterDownloaded,
fallbackLabel = stringResource(R.string.transition_no_next),
fallbackLabel = localize(MR.strings.transition_no_next),
chapterGap = calculateChapterGap(goingToChapter?.toDomainChapter(), currChapter.toDomainChapter()),
)
}
@ -191,7 +191,7 @@ private fun ChapterGapWarning(
)
Text(
text = pluralStringResource(R.plurals.missing_chapters_warning, count = gapCount, gapCount),
text = localizePlural(MR.plurals.missing_chapters_warning, count = gapCount, gapCount),
style = MaterialTheme.typography.bodyMedium,
)
}
@ -245,7 +245,7 @@ private fun ChapterText(
) {
Icon(
imageVector = Icons.Filled.CheckCircle,
contentDescription = stringResource(R.string.label_downloaded),
contentDescription = localize(MR.strings.label_downloaded),
)
},
),

View File

@ -12,18 +12,19 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.manga.model.readerOrientation
import eu.kanade.presentation.components.AdaptiveSheet
import eu.kanade.presentation.reader.components.ModeSelectionDialog
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.SettingsIconGrid
import tachiyomi.presentation.core.components.material.IconToggleButton
import tachiyomi.presentation.core.i18n.localize
private val ReaderOrientationsWithoutDefault = ReaderOrientation.entries - ReaderOrientation.DEFAULT
@ -31,7 +32,7 @@ private val ReaderOrientationsWithoutDefault = ReaderOrientation.entries - Reade
fun OrientationSelectDialog(
onDismissRequest: () -> Unit,
screenModel: ReaderSettingsScreenModel,
onChange: (Int) -> Unit,
onChange: (StringResource) -> Unit,
) {
val manga by screenModel.mangaFlow.collectAsState()
val orientation = remember(manga) { ReaderOrientation.fromPreference(manga?.readerOrientation?.toInt()) }
@ -63,7 +64,7 @@ private fun DialogContent(
}.takeIf { orientation != ReaderOrientation.DEFAULT },
onApply = { onChangeOrientation(selected) },
) {
SettingsIconGrid(R.string.rotation_type) {
SettingsIconGrid(MR.strings.rotation_type) {
items(ReaderOrientationsWithoutDefault) { mode ->
IconToggleButton(
checked = mode == selected,
@ -72,7 +73,7 @@ private fun DialogContent(
},
modifier = Modifier.fillMaxWidth(),
imageVector = ImageVector.vectorResource(mode.iconRes),
title = stringResource(mode.stringRes),
title = localize(mode.stringRes),
)
}
}

View File

@ -12,18 +12,19 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.manga.model.readingMode
import eu.kanade.presentation.components.AdaptiveSheet
import eu.kanade.presentation.reader.components.ModeSelectionDialog
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.SettingsIconGrid
import tachiyomi.presentation.core.components.material.IconToggleButton
import tachiyomi.presentation.core.i18n.localize
private val ReadingModesWithoutDefault = ReadingMode.entries - ReadingMode.DEFAULT
@ -31,7 +32,7 @@ private val ReadingModesWithoutDefault = ReadingMode.entries - ReadingMode.DEFAU
fun ReadingModeSelectDialog(
onDismissRequest: () -> Unit,
screenModel: ReaderSettingsScreenModel,
onChange: (Int) -> Unit,
onChange: (StringResource) -> Unit,
) {
val manga by screenModel.mangaFlow.collectAsState()
val readingMode = remember(manga) { ReadingMode.fromPreference(manga?.readingMode?.toInt()) }
@ -59,7 +60,7 @@ private fun DialogContent(
onUseDefault = { onChangeReadingMode(ReadingMode.DEFAULT) }.takeIf { readingMode != ReadingMode.DEFAULT },
onApply = { onChangeReadingMode(selected) },
) {
SettingsIconGrid(R.string.pref_category_reading_mode) {
SettingsIconGrid(MR.strings.pref_category_reading_mode) {
items(ReadingModesWithoutDefault) { mode ->
IconToggleButton(
checked = mode == selected,
@ -68,7 +69,7 @@ private fun DialogContent(
},
modifier = Modifier.fillMaxWidth(),
imageVector = ImageVector.vectorResource(mode.iconRes),
title = stringResource(mode.stringRes),
title = localize(mode.stringRes),
)
}
}

View File

@ -17,12 +17,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.ReaderBottomButton
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun BottomReaderBar(
@ -60,7 +61,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickChapterList) {
Icon(
imageVector = Icons.Outlined.FormatListNumbered,
contentDescription = stringResource(R.string.chapters),
contentDescription = localize(MR.strings.chapters),
)
}
}
@ -69,7 +70,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickWebView) {
Icon(
imageVector = Icons.Outlined.Public,
contentDescription = stringResource(R.string.action_open_in_web_view),
contentDescription = localize(MR.strings.action_open_in_web_view),
)
}
}
@ -78,7 +79,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickShare) {
Icon(
imageVector = Icons.Outlined.Share,
contentDescription = stringResource(R.string.action_share),
contentDescription = localize(MR.strings.action_share),
)
}
}
@ -87,7 +88,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickReadingMode) {
Icon(
painter = painterResource(readingMode.iconRes),
contentDescription = stringResource(R.string.viewer),
contentDescription = localize(MR.strings.viewer),
)
}
}
@ -96,7 +97,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickOrientation) {
Icon(
painter = painterResource(orientation.iconRes),
contentDescription = stringResource(R.string.pref_rotation_type),
contentDescription = localize(MR.strings.pref_rotation_type),
)
}
}
@ -110,7 +111,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickCropBorder) {
Icon(
painter = painterResource(if (cropEnabled) R.drawable.ic_crop_24dp else R.drawable.ic_crop_off_24dp),
contentDescription = stringResource(R.string.pref_crop_borders),
contentDescription = localize(MR.strings.pref_crop_borders),
)
}
}
@ -123,7 +124,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickPageLayout) {
Icon(
painter = painterResource(R.drawable.ic_book_open_variant_24dp),
contentDescription = stringResource(R.string.page_layout),
contentDescription = localize(MR.strings.page_layout),
)
}
}
@ -132,7 +133,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickShiftPage) {
Icon(
painter = painterResource(R.drawable.ic_page_next_outline_24dp),
contentDescription = stringResource(R.string.shift_double_pages),
contentDescription = localize(MR.strings.shift_double_pages),
)
}
}
@ -140,7 +141,7 @@ fun BottomReaderBar(
IconButton(onClick = onClickSettings) {
Icon(
imageVector = Icons.Outlined.Settings,
contentDescription = stringResource(R.string.action_settings),
contentDescription = localize(MR.stringss.action_settings),
)
}
// SY <--

View File

@ -16,12 +16,12 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.SettingsItemsPaddings
import tachiyomi.presentation.core.i18n.localize
@Composable
fun ModeSelectionDialog(
@ -40,7 +40,7 @@ fun ModeSelectionDialog(
) {
onUseDefault?.let {
OutlinedButton(onClick = it) {
Text(text = stringResource(R.string.action_revert_to_default))
Text(text = localize(MR.strings.action_revert_to_default))
}
}
@ -57,7 +57,7 @@ fun ModeSelectionDialog(
imageVector = Icons.Outlined.Check,
contentDescription = null,
)
Text(text = stringResource(R.string.action_apply))
Text(text = localize(MR.strings.action_apply))
}
}
}

View File

@ -6,17 +6,17 @@ import androidx.compose.material3.FilterChip
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.res.stringResource
import androidx.core.graphics.alpha
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import tachiyomi.core.preference.getAndSet
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.CheckboxItem
import tachiyomi.presentation.core.components.SettingsChipRow
import tachiyomi.presentation.core.components.SliderItem
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.collectAsState
@Composable
@ -24,25 +24,25 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
val colorFilterModes = buildList {
addAll(
listOf(
R.string.label_default,
R.string.filter_mode_multiply,
R.string.filter_mode_screen,
MR.strings.label_default,
MR.strings.filter_mode_multiply,
MR.strings.filter_mode_screen,
),
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
addAll(
listOf(
R.string.filter_mode_overlay,
R.string.filter_mode_lighten,
R.string.filter_mode_darken,
MR.strings.filter_mode_overlay,
MR.strings.filter_mode_lighten,
MR.strings.filter_mode_darken,
),
)
}
}.map { stringResource(it) }
}.map { localize(it) }
val customBrightness by screenModel.preferences.customBrightness().collectAsState()
CheckboxItem(
label = stringResource(R.string.pref_custom_brightness),
label = localize(MR.strings.pref_custom_brightness),
pref = screenModel.preferences.customBrightness(),
)
@ -55,7 +55,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
if (customBrightness) {
val customBrightnessValue by screenModel.preferences.customBrightnessValue().collectAsState()
SliderItem(
label = stringResource(R.string.pref_custom_brightness),
label = localize(MR.strings.pref_custom_brightness),
min = -75,
max = 100,
value = customBrightnessValue,
@ -66,13 +66,13 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
val colorFilter by screenModel.preferences.colorFilter().collectAsState()
CheckboxItem(
label = stringResource(R.string.pref_custom_color_filter),
label = localize(MR.strings.pref_custom_color_filter),
pref = screenModel.preferences.colorFilter(),
)
if (colorFilter) {
val colorFilterValue by screenModel.preferences.colorFilterValue().collectAsState()
SliderItem(
label = stringResource(R.string.color_filter_r_value),
label = localize(MR.strings.color_filter_r_value),
max = 255,
value = colorFilterValue.red,
valueText = colorFilterValue.red.toString(),
@ -83,7 +83,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
},
)
SliderItem(
label = stringResource(R.string.color_filter_g_value),
label = localize(MR.strings.color_filter_g_value),
max = 255,
value = colorFilterValue.green,
valueText = colorFilterValue.green.toString(),
@ -94,7 +94,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
},
)
SliderItem(
label = stringResource(R.string.color_filter_b_value),
label = localize(MR.strings.color_filter_b_value),
max = 255,
value = colorFilterValue.blue,
valueText = colorFilterValue.blue.toString(),
@ -105,7 +105,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
},
)
SliderItem(
label = stringResource(R.string.color_filter_a_value),
label = localize(MR.strings.color_filter_a_value),
max = 255,
value = colorFilterValue.alpha,
valueText = colorFilterValue.alpha.toString(),
@ -117,7 +117,7 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
)
val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()
SettingsChipRow(R.string.pref_color_filter_mode) {
SettingsChipRow(MR.strings.pref_color_filter_mode) {
colorFilterModes.mapIndexed { index, it ->
FilterChip(
selected = colorFilterMode == index,
@ -129,11 +129,11 @@ internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel)
}
CheckboxItem(
label = stringResource(R.string.pref_grayscale),
label = localize(MR.strings.pref_grayscale),
pref = screenModel.preferences.grayscale(),
)
CheckboxItem(
label = stringResource(R.string.pref_inverted_colors),
label = localize(MR.strings.pref_inverted_colors),
pref = screenModel.preferences.invertedColors(),
)
}

View File

@ -11,13 +11,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.window.DialogWindowProvider
import eu.kanade.presentation.components.TabbedDialog
import eu.kanade.presentation.components.TabbedDialogPaddings
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import kotlinx.collections.immutable.persistentListOf
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun ReaderSettingsDialog(
@ -27,9 +27,9 @@ fun ReaderSettingsDialog(
screenModel: ReaderSettingsScreenModel,
) {
val tabTitles = persistentListOf(
stringResource(R.string.pref_category_reading_mode),
stringResource(R.string.pref_category_general),
stringResource(R.string.custom_filter),
localize(MR.strings.pref_category_reading_mode),
localize(MR.strings.pref_category_general),
localize(MR.strings.custom_filter),
)
val pagerState = rememberPagerState { tabTitles.size }

View File

@ -7,45 +7,45 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.res.stringResource
import eu.kanade.domain.manga.model.readerOrientation
import eu.kanade.domain.manga.model.readingMode
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.CheckboxItem
import tachiyomi.presentation.core.components.HeadingItem
import tachiyomi.presentation.core.components.SettingsChipRow
import tachiyomi.presentation.core.components.SliderItem
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.collectAsState
import java.text.NumberFormat
@Composable
internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) {
HeadingItem(R.string.pref_category_for_this_series)
HeadingItem(MR.strings.pref_category_for_this_series)
val manga by screenModel.mangaFlow.collectAsState()
val readingMode = remember(manga) { ReadingMode.fromPreference(manga?.readingMode?.toInt()) }
SettingsChipRow(R.string.pref_category_reading_mode) {
SettingsChipRow(MR.strings.pref_category_reading_mode) {
ReadingMode.entries.map {
FilterChip(
selected = it == readingMode,
onClick = { screenModel.onChangeReadingMode(it) },
label = { Text(stringResource(it.stringRes)) },
label = { Text(localize(it.stringRes)) },
)
}
}
val orientation = remember(manga) { ReaderOrientation.fromPreference(manga?.readerOrientation?.toInt()) }
SettingsChipRow(R.string.rotation_type) {
SettingsChipRow(MR.strings.rotation_type) {
ReaderOrientation.entries.map {
FilterChip(
selected = it == orientation,
onClick = { screenModel.onChangeOrientation(it) },
label = { Text(stringResource(it.stringRes)) },
label = { Text(localize(it.stringRes)) },
)
}
}
@ -63,7 +63,7 @@ internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel)
@Composable
private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenModel) {
HeadingItem(R.string.pager_viewer)
HeadingItem(MR.strings.pager_viewer)
val navigationModePager by screenModel.preferences.navigationModePager().collectAsState()
val pagerNavInverted by screenModel.preferences.pagerNavInverted().collectAsState()
@ -75,23 +75,23 @@ private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenMod
)
val imageScaleType by screenModel.preferences.imageScaleType().collectAsState()
SettingsChipRow(R.string.pref_image_scale_type) {
SettingsChipRow(MR.strings.pref_image_scale_type) {
ReaderPreferences.ImageScaleType.mapIndexed { index, it ->
FilterChip(
selected = imageScaleType == index + 1,
onClick = { screenModel.preferences.imageScaleType().set(index + 1) },
label = { Text(stringResource(it)) },
label = { Text(localize(it)) },
)
}
}
val zoomStart by screenModel.preferences.zoomStart().collectAsState()
SettingsChipRow(R.string.pref_zoom_start) {
SettingsChipRow(MR.strings.pref_zoom_start) {
ReaderPreferences.ZoomStart.mapIndexed { index, it ->
FilterChip(
selected = zoomStart == index + 1,
onClick = { screenModel.preferences.zoomStart().set(index + 1) },
label = { Text(stringResource(it)) },
label = { Text(localize(it)) },
)
}
}
@ -110,42 +110,42 @@ private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenMod
// SY <--
CheckboxItem(
label = stringResource(R.string.pref_crop_borders),
label = localize(MR.strings.pref_crop_borders),
pref = screenModel.preferences.cropBorders(),
)
CheckboxItem(
label = stringResource(R.string.pref_landscape_zoom),
label = localize(MR.strings.pref_landscape_zoom),
pref = screenModel.preferences.landscapeZoom(),
)
CheckboxItem(
label = stringResource(R.string.pref_navigate_pan),
label = localize(MR.strings.pref_navigate_pan),
pref = screenModel.preferences.navigateToPan(),
)
val dualPageSplitPaged by screenModel.preferences.dualPageSplitPaged().collectAsState()
CheckboxItem(
label = stringResource(R.string.pref_dual_page_split),
label = localize(MR.strings.pref_dual_page_split),
pref = screenModel.preferences.dualPageSplitPaged(),
)
if (dualPageSplitPaged) {
CheckboxItem(
label = stringResource(R.string.pref_dual_page_invert),
label = localize(MR.strings.pref_dual_page_invert),
pref = screenModel.preferences.dualPageInvertPaged(),
)
}
val dualPageRotateToFit by screenModel.preferences.dualPageRotateToFit().collectAsState()
CheckboxItem(
label = stringResource(R.string.pref_page_rotate),
label = localize(MR.strings.pref_page_rotate),
pref = screenModel.preferences.dualPageRotateToFit(),
)
if (dualPageRotateToFit) {
CheckboxItem(
label = stringResource(R.string.pref_page_rotate_invert),
label = localize(MR.strings.pref_page_rotate_invert),
pref = screenModel.preferences.dualPageRotateToFitInvert(),
)
}
@ -178,7 +178,7 @@ private fun ColumnScope.PagerViewerSettings(screenModel: ReaderSettingsScreenMod
private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenModel) {
val numberFormat = remember { NumberFormat.getPercentInstance() }
HeadingItem(R.string.webtoon_viewer)
HeadingItem(MR.strings.webtoon_viewer)
val navigationModeWebtoon by screenModel.preferences.navigationModeWebtoon().collectAsState()
val webtoonNavInverted by screenModel.preferences.webtoonNavInverted().collectAsState()
@ -191,7 +191,7 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM
val webtoonSidePadding by screenModel.preferences.webtoonSidePadding().collectAsState()
SliderItem(
label = stringResource(R.string.pref_webtoon_side_padding),
label = localize(MR.strings.pref_webtoon_side_padding),
min = ReaderPreferences.WEBTOON_PADDING_MIN,
max = ReaderPreferences.WEBTOON_PADDING_MAX,
value = webtoonSidePadding,
@ -202,7 +202,7 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM
)
CheckboxItem(
label = stringResource(R.string.pref_crop_borders),
label = localize(MR.strings.pref_crop_borders),
pref = screenModel.preferences.cropBordersWebtoon(),
)
@ -225,19 +225,19 @@ private fun ColumnScope.WebtoonViewerSettings(screenModel: ReaderSettingsScreenM
val dualPageSplitWebtoon by screenModel.preferences.dualPageSplitWebtoon().collectAsState()
CheckboxItem(
label = stringResource(R.string.pref_dual_page_split),
label = localize(MR.strings.pref_dual_page_split),
pref = screenModel.preferences.dualPageSplitWebtoon(),
)
if (dualPageSplitWebtoon) {
CheckboxItem(
label = stringResource(R.string.pref_dual_page_invert),
label = localize(MR.strings.pref_dual_page_invert),
pref = screenModel.preferences.dualPageInvertWebtoon(),
)
}
CheckboxItem(
label = stringResource(R.string.pref_double_tap_zoom),
label = localize(MR.strings.pref_double_tap_zoom),
pref = screenModel.preferences.webtoonDoubleTapZoomEnabled(),
)
}
@ -261,23 +261,23 @@ private fun ColumnScope.TapZonesItems(
invertMode: ReaderPreferences.TappingInvertMode,
onSelectInvertMode: (ReaderPreferences.TappingInvertMode) -> Unit,
) {
SettingsChipRow(R.string.pref_viewer_nav) {
SettingsChipRow(MR.strings.pref_viewer_nav) {
ReaderPreferences.TapZones.mapIndexed { index, it ->
FilterChip(
selected = selected == index,
onClick = { onSelect(index) },
label = { Text(stringResource(it)) },
label = { Text(localize(it)) },
)
}
}
if (selected != 5) {
SettingsChipRow(R.string.pref_read_with_tapping_inverted) {
SettingsChipRow(MR.strings.pref_read_with_tapping_inverted) {
ReaderPreferences.TappingInvertMode.entries.map {
FilterChip(
selected = it == invertMode,
onClick = { onSelectInvertMode(it) },
label = { Text(stringResource(it.titleResId)) },
label = { Text(localize(it.titleRes)) },
)
}
}

View File

@ -1,6 +1,5 @@
package eu.kanade.presentation.track
import androidx.annotation.StringRes
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@ -42,20 +41,21 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.StringResource
import eu.kanade.domain.track.model.toDbTrack
import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.presentation.track.components.TrackLogoIcon
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.Tracker
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
import eu.kanade.tachiyomi.util.system.copyToClipboard
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import java.text.DateFormat
private const val UnsetStatusTextAlpha = 0.5F
@ -131,7 +131,7 @@ fun TrackInfoDialogHome(
private fun TrackInfoItem(
title: String,
tracker: Tracker,
@StringRes status: Int?,
status: StringResource?,
onStatusClick: () -> Unit,
chapters: String,
onChaptersClick: () -> Unit,
@ -194,7 +194,7 @@ private fun TrackInfoItem(
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
TrackDetailsItem(
modifier = Modifier.weight(1f),
text = status?.let { stringResource(it) } ?: "",
text = status?.let { localize(it) } ?: "",
onClick = onStatusClick,
)
VerticalDivider()
@ -209,7 +209,7 @@ private fun TrackInfoItem(
modifier = Modifier
.weight(1f)
.alpha(if (score == null) UnsetStatusTextAlpha else 1f),
text = score ?: stringResource(R.string.score),
text = score ?: localize(MR.strings.score),
onClick = onScoreClick,
)
}
@ -221,14 +221,14 @@ private fun TrackInfoItem(
TrackDetailsItem(
modifier = Modifier.weight(1F),
text = startDate,
placeholder = stringResource(R.string.track_started_reading_date),
placeholder = localize(MR.strings.track_started_reading_date),
onClick = onStartDateClick,
)
VerticalDivider()
TrackDetailsItem(
modifier = Modifier.weight(1F),
text = endDate,
placeholder = stringResource(R.string.track_finished_reading_date),
placeholder = localize(MR.strings.track_finished_reading_date),
onClick = onEndDateClick,
)
}
@ -279,7 +279,7 @@ private fun TrackInfoItemEmpty(
.padding(start = 16.dp)
.weight(1f),
) {
Text(text = stringResource(R.string.add_tracking))
Text(text = localize(MR.strings.add_tracking))
}
}
}
@ -294,7 +294,7 @@ private fun TrackInfoItemMenu(
IconButton(onClick = { expanded = true }) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = stringResource(R.string.label_more),
contentDescription = localize(MR.strings.label_more),
)
}
DropdownMenu(
@ -302,14 +302,14 @@ private fun TrackInfoItemMenu(
onDismissRequest = { expanded = false },
) {
DropdownMenuItem(
text = { Text(stringResource(R.string.action_open_in_browser)) },
text = { Text(localize(MR.strings.action_open_in_browser)) },
onClick = {
onOpenInBrowser()
expanded = false
},
)
DropdownMenuItem(
text = { Text(stringResource(R.string.action_remove)) },
text = { Text(localize(MR.strings.action_remove)) },
onClick = {
onRemoved()
expanded = false

View File

@ -29,18 +29,19 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import dev.icerock.moko.resources.StringResource
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.components.WheelNumberPicker
import tachiyomi.presentation.core.components.WheelTextPicker
import tachiyomi.presentation.core.components.material.AlertDialogContent
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.isScrolledToEnd
import tachiyomi.presentation.core.util.isScrolledToStart
@ -48,12 +49,12 @@ import tachiyomi.presentation.core.util.isScrolledToStart
fun TrackStatusSelector(
selection: Int,
onSelectionChange: (Int) -> Unit,
selections: Map<Int, Int?>,
selections: Map<Int, StringResource?>,
onConfirm: () -> Unit,
onDismissRequest: () -> Unit,
) {
BaseSelector(
title = stringResource(R.string.status),
title = localize(MR.strings.status),
content = {
val state = rememberLazyListState()
ScrollbarLazyColumn(state = state) {
@ -76,7 +77,7 @@ fun TrackStatusSelector(
onClick = null,
)
Text(
text = value?.let { stringResource(it) } ?: "",
text = value?.let { localize(it) } ?: "",
style = MaterialTheme.typography.bodyLarge.merge(),
modifier = Modifier.padding(start = 24.dp),
)
@ -101,7 +102,7 @@ fun TrackChapterSelector(
onDismissRequest: () -> Unit,
) {
BaseSelector(
title = stringResource(R.string.chapters),
title = localize(MR.strings.chapters),
content = {
WheelNumberPicker(
items = range.toImmutableList(),
@ -124,7 +125,7 @@ fun TrackScoreSelector(
onDismissRequest: () -> Unit,
) {
BaseSelector(
title = stringResource(R.string.score),
title = localize(MR.strings.score),
content = {
WheelTextPicker(
items = selections,
@ -171,15 +172,15 @@ fun TrackDateSelector(
) {
if (onRemove != null) {
TextButton(onClick = onRemove) {
Text(text = stringResource(R.string.action_remove))
Text(text = localize(MR.strings.action_remove))
}
Spacer(modifier = Modifier.weight(1f))
}
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
TextButton(onClick = { onConfirm(pickerState.selectedDateMillis!!) }) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
}
}
@ -214,10 +215,10 @@ private fun BaseSelector(
Spacer(modifier = Modifier.weight(1f))
}
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
TextButton(onClick = onConfirm) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
}
},
@ -234,12 +235,12 @@ private fun TrackStatusSelectorPreviews() {
onSelectionChange = {},
selections = mapOf(
// Anilist values
1 to R.string.reading,
2 to R.string.plan_to_read,
3 to R.string.completed,
4 to R.string.on_hold,
5 to R.string.dropped,
6 to R.string.repeating,
1 to MR.strings.reading,
2 to MR.strings.plan_to_read,
3 to MR.strings.completed,
4 to MR.strings.on_hold,
5 to MR.strings.dropped,
6 to MR.strings.repeating,
),
onConfirm = {},
onDismissRequest = {},

View File

@ -29,7 +29,6 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Button
@ -50,7 +49,6 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.TextFieldValue
@ -62,11 +60,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.manga.components.MangaCover
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.LoadingScreen
import tachiyomi.presentation.core.util.plus
@ -121,7 +120,7 @@ fun TrackerSearch(
decorationBox = {
if (query.text.isEmpty()) {
Text(
text = stringResource(R.string.action_search_hint),
text = localize(MR.strings.action_search_hint),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyLarge,
)
@ -164,7 +163,7 @@ fun TrackerSearch(
.fillMaxWidth(),
elevation = ButtonDefaults.elevatedButtonElevation(),
) {
Text(text = stringResource(R.string.action_track))
Text(text = localize(MR.strings.action_track))
}
}
},
@ -177,7 +176,7 @@ fun TrackerSearch(
if (availableTracks.isEmpty()) {
EmptyScreen(
modifier = Modifier.padding(innerPadding),
textResource = R.string.no_results_found,
stringRes = MR.strings.no_results_found,
)
} else {
ScrollbarLazyColumn(
@ -205,7 +204,7 @@ fun TrackerSearch(
EmptyScreen(
modifier = Modifier.padding(innerPadding),
message = queryResult.exceptionOrNull()?.message
?: stringResource(R.string.unknown_error),
?: localize(MR.strings.unknown_error),
)
}
}
@ -264,19 +263,19 @@ private fun SearchResultItem(
)
if (type.isNotBlank()) {
SearchResultItemDetails(
title = stringResource(R.string.track_type),
title = localize(MR.strings.track_type),
text = type,
)
}
if (startDate.isNotBlank()) {
SearchResultItemDetails(
title = stringResource(R.string.label_started),
title = localize(MR.strings.label_started),
text = startDate,
)
}
if (status.isNotBlank()) {
SearchResultItemDetails(
title = stringResource(R.string.track_status),
title = localize(MR.strings.track_status),
text = status,
)
}

View File

@ -4,8 +4,8 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
@Composable
fun UpdatesDeleteConfirmationDialog(
@ -14,7 +14,7 @@ fun UpdatesDeleteConfirmationDialog(
) {
AlertDialog(
text = {
Text(text = stringResource(R.string.confirm_delete_chapters))
Text(text = localize(MR.strings.confirm_delete_chapters))
},
onDismissRequest = onDismissRequest,
confirmButton = {
@ -22,12 +22,12 @@ fun UpdatesDeleteConfirmationDialog(
onConfirm()
onDismissRequest()
}) {
Text(text = stringResource(R.string.action_ok))
Text(text = localize(MR.strings.action_ok))
}
},
dismissButton = {
TextButton(onClick = onDismissRequest) {
Text(text = stringResource(R.string.action_cancel))
Text(text = localize(MR.strings.action_cancel))
}
},
)

View File

@ -18,23 +18,23 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.util.fastAny
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.manga.components.ChapterDownloadAction
import eu.kanade.presentation.manga.components.MangaBottomActionMenu
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.updates.UpdatesItem
import eu.kanade.tachiyomi.ui.updates.UpdatesScreenModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.material.PullRefresh
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.screens.LoadingScreen
import kotlin.time.Duration.Companion.seconds
@ -88,7 +88,7 @@ fun UpdateScreen(
when {
state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
state.items.isEmpty() -> EmptyScreen(
textResource = R.string.information_no_recent,
stringRes = MR.strings.information_no_recent,
modifier = Modifier.padding(contentPadding),
)
else -> {
@ -146,12 +146,12 @@ private fun UpdatesAppBar(
) {
AppBar(
modifier = modifier,
title = stringResource(R.string.label_recent_updates),
title = localize(MR.strings.label_recent_updates),
actions = {
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_update_library),
title = localize(MR.strings.action_update_library),
icon = Icons.Outlined.Refresh,
onClick = onUpdateLibrary,
),
@ -164,12 +164,12 @@ private fun UpdatesAppBar(
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_select_all),
title = localize(MR.strings.action_select_all),
icon = Icons.Outlined.SelectAll,
onClick = onSelectAll,
),
AppBar.Action(
title = stringResource(R.string.action_select_inverse),
title = localize(MR.strings.action_select_inverse),
icon = Icons.Outlined.FlipToBack,
onClick = onInvertSelection,
),

View File

@ -29,7 +29,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@ -38,13 +37,14 @@ import eu.kanade.presentation.manga.components.ChapterDownloadIndicator
import eu.kanade.presentation.manga.components.DotSeparatorText
import eu.kanade.presentation.manga.components.MangaCover
import eu.kanade.presentation.util.relativeTimeSpanString
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.ui.updates.UpdatesItem
import tachiyomi.domain.updates.model.UpdatesWithRelations
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.ListGroupHeader
import tachiyomi.presentation.core.components.material.ReadItemAlpha
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.localize
import tachiyomi.presentation.core.util.selectedBackground
internal fun LazyListScope.updatesLastUpdatedItem(
@ -56,7 +56,7 @@ internal fun LazyListScope.updatesLastUpdatedItem(
.padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
) {
Text(
text = stringResource(R.string.updates_last_update_info, relativeTimeSpanString(lastUpdated)),
text = localize(MR.strings.updates_last_update_info, relativeTimeSpanString(lastUpdated)),
fontStyle = FontStyle.Italic,
)
}
@ -107,8 +107,8 @@ internal fun LazyListScope.updatesUiItems(
)/* SY <-- */ && it > 0L
}
?.let {
stringResource(
R.string.chapter_progress,
localize(
MR.strings.chapter_progress,
it + 1,
)
},
@ -190,7 +190,7 @@ private fun UpdatesUiItem(
if (!update.read) {
Icon(
imageVector = Icons.Filled.Circle,
contentDescription = stringResource(R.string.unread),
contentDescription = localize(MR.strings.unread),
modifier = Modifier
.height(8.dp)
.padding(end = 4.dp),
@ -200,7 +200,7 @@ private fun UpdatesUiItem(
if (update.bookmark) {
Icon(
imageVector = Icons.Filled.Bookmark,
contentDescription = stringResource(R.string.action_filter_bookmarked),
contentDescription = localize(MR.strings.action_filter_bookmarked),
modifier = Modifier
.sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }),
tint = MaterialTheme.colorScheme.primary,

View File

@ -1,30 +1,31 @@
package eu.kanade.presentation.util
import android.content.Context
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.network.HttpException
import eu.kanade.tachiyomi.source.online.LicensedMangaChaptersException
import eu.kanade.tachiyomi.util.system.isOnline
import tachiyomi.core.i18n.localize
import tachiyomi.data.source.NoResultsException
import tachiyomi.domain.source.model.SourceNotInstalledException
import tachiyomi.i18n.MR
import java.net.UnknownHostException
context(Context)
val Throwable.formattedMessage: String
get() {
when (this) {
is HttpException -> return getString(R.string.exception_http, code)
is HttpException -> return localize(MR.strings.exception_http, code)
is UnknownHostException -> {
return if (!isOnline()) {
getString(R.string.exception_offline)
localize(MR.strings.exception_offline)
} else {
getString(R.string.exception_unknown_host, message)
localize(MR.strings.exception_unknown_host, message ?: "")
}
}
is NoResultsException -> return getString(R.string.no_results_found)
is SourceNotInstalledException -> return getString(R.string.loader_not_implemented_error)
is LicensedMangaChaptersException -> return getString(R.string.licensed_manga_chapters_error)
is NoResultsException -> return localize(MR.strings.no_results_found)
is SourceNotInstalledException -> return localize(MR.strings.loader_not_implemented_error)
is LicensedMangaChaptersException -> return localize(MR.strings.licensed_manga_chapters_error)
}
return when (val className = this::class.simpleName) {
"Exception", "IOException" -> message ?: className

View File

@ -4,8 +4,9 @@ import android.content.Context
import android.text.format.DateUtils
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.res.stringResource
import eu.kanade.tachiyomi.R
import tachiyomi.core.i18n.localize
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.localize
import java.util.Date
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes
@ -13,10 +14,10 @@ import kotlin.time.Duration.Companion.minutes
fun Duration.toDurationString(context: Context, fallback: String): String {
return toComponents { days, hours, minutes, seconds, _ ->
buildList(4) {
if (days != 0L) add(context.getString(R.string.day_short, days))
if (hours != 0) add(context.getString(R.string.hour_short, hours))
if (minutes != 0 && (days == 0L || hours == 0)) add(context.getString(R.string.minute_short, minutes))
if (seconds != 0 && days == 0L && hours == 0) add(context.getString(R.string.seconds_short, seconds))
if (days != 0L) add(context.localize(MR.strings.day_short, days))
if (hours != 0) add(context.localize(MR.strings.hour_short, hours))
if (minutes != 0 && (days == 0L || hours == 0)) add(context.localize(MR.strings.minute_short, minutes))
if (seconds != 0 && days == 0L && hours == 0) add(context.localize(MR.strings.seconds_short, seconds))
}.joinToString(" ").ifBlank { fallback }
}
}
@ -26,8 +27,8 @@ fun Duration.toDurationString(context: Context, fallback: String): String {
fun relativeTimeSpanString(epochMillis: Long): String {
val now = Date().time
return when {
epochMillis <= 0L -> stringResource(R.string.relative_time_span_never)
now - epochMillis < 1.minutes.inWholeMilliseconds -> stringResource(R.string.updates_last_update_info_just_now)
epochMillis <= 0L -> localize(MR.strings.relative_time_span_never)
now - epochMillis < 1.minutes.inWholeMilliseconds -> localize(MR.strings.updates_last_update_info_just_now)
else -> DateUtils.getRelativeTimeSpanString(epochMillis, now, DateUtils.MINUTE_IN_MILLIS).toString()
}
}

View File

@ -13,8 +13,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.automirrored.outlined.ArrowForward
import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.ArrowForward
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
@ -29,7 +27,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.web.AccompanistWebViewClient
import com.google.accompanist.web.LoadingState
@ -40,12 +37,13 @@ import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.WarningBanner
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.getHtml
import eu.kanade.tachiyomi.util.system.setDefaultSettings
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
import tachiyomi.presentation.core.i18n.localize
@Composable
fun WebViewScreenContent(
@ -127,7 +125,7 @@ fun WebViewScreenContent(
AppBarActions(
persistentListOf(
AppBar.Action(
title = stringResource(R.string.action_webview_back),
title = localize(MR.strings.action_webview_back),
icon = Icons.AutoMirrored.Outlined.ArrowBack,
onClick = {
if (navigator.canGoBack) {
@ -137,7 +135,7 @@ fun WebViewScreenContent(
enabled = navigator.canGoBack,
),
AppBar.Action(
title = stringResource(R.string.action_webview_forward),
title = localize(MR.strings.action_webview_forward),
icon = Icons.AutoMirrored.Outlined.ArrowForward,
onClick = {
if (navigator.canGoForward) {
@ -147,19 +145,19 @@ fun WebViewScreenContent(
enabled = navigator.canGoForward,
),
AppBar.OverflowAction(
title = stringResource(R.string.action_webview_refresh),
title = localize(MR.strings.action_webview_refresh),
onClick = { navigator.reload() },
),
AppBar.OverflowAction(
title = stringResource(R.string.action_share),
title = localize(MR.strings.action_share),
onClick = { onShare(currentUrl) },
),
AppBar.OverflowAction(
title = stringResource(R.string.action_open_in_browser),
title = localize(MR.strings.action_open_in_browser),
onClick = { onOpenInBrowser(currentUrl) },
),
AppBar.OverflowAction(
title = stringResource(R.string.pref_clear_cookies),
title = localize(MR.strings.pref_clear_cookies),
onClick = { onClearCookies(currentUrl) },
),
),
@ -172,7 +170,7 @@ fun WebViewScreenContent(
modifier = Modifier.padding(8.dp),
) {
WarningBanner(
textRes = R.string.information_cloudflare_help,
textRes = MR.strings.information_cloudflare_help,
modifier = Modifier
.clip(MaterialTheme.shapes.small)
.clickable {

View File

@ -68,7 +68,9 @@ import kotlinx.coroutines.flow.onEach
import logcat.LogPriority
import logcat.LogcatLogger
import org.conscrypt.Conscrypt
import tachiyomi.core.i18n.localize
import tachiyomi.core.util.system.logcat
import tachiyomi.i18n.MR
import tachiyomi.presentation.widget.WidgetManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -127,8 +129,8 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
Notifications.ID_INCOGNITO_MODE,
Notifications.CHANNEL_INCOGNITO_MODE,
) {
setContentTitle(getString(R.string.pref_incognito_mode))
setContentText(getString(R.string.notification_incognito_text))
setContentTitle(localize(MR.strings.pref_incognito_mode))
setContentText(localize(MR.strings.notification_incognito_text))
setSmallIcon(R.drawable.ic_glasses_24dp)
setOngoing(true)

View File

@ -27,6 +27,7 @@ import tachiyomi.core.preference.plusAssign
import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
import tachiyomi.i18n.MR
import java.io.File
object Migrations {
@ -148,7 +149,7 @@ object Migrations {
// v53: switched from WebView to OAuth
if (trackerManager.myAnimeList.isLoggedIn) {
trackerManager.myAnimeList.logout()
context.toast(R.string.myanimelist_relogin)
context.toast(MR.strings.myanimelist_relogin)
}
}
if (oldVersion < 57) {

View File

@ -4,7 +4,6 @@ import android.Manifest
import android.content.Context
import android.net.Uri
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_APP_PREFS
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CATEGORY
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CHAPTER
@ -47,6 +46,7 @@ import logcat.LogPriority
import okio.buffer
import okio.gzip
import okio.sink
import tachiyomi.core.i18n.localize
import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.util.system.logcat
@ -62,6 +62,7 @@ import tachiyomi.domain.manga.interactor.GetFlatMetadataById
import tachiyomi.domain.manga.interactor.GetMergedManga
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.FileOutputStream
@ -94,7 +95,7 @@ class BackupCreator(
*/
suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
if (!context.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
throw IllegalStateException(context.getString(R.string.missing_storage_permission))
throw IllegalStateException(context.localize(MR.strings.missing_storage_permission))
}
val databaseManga = getFavorites.await() /* SY --> */ +
@ -137,7 +138,7 @@ class BackupCreator(
UniFile.fromUri(context, uri)
}
)
?: throw Exception(context.getString(R.string.create_backup_file_error))
?: throw Exception(context.localize(MR.strings.create_backup_file_error))
if (!file.isFile) {
throw IllegalStateException("Failed to get handle on a backup file")
@ -145,7 +146,7 @@ class BackupCreator(
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
if (byteArray.isEmpty()) {
throw IllegalStateException(context.getString(R.string.empty_backup_error))
throw IllegalStateException(context.localize(MR.strings.empty_backup_error))
}
file.openOutputStream().also {

View File

@ -2,10 +2,11 @@ package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.TrackerManager
import eu.kanade.tachiyomi.util.BackupUtil
import tachiyomi.core.i18n.localize
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -28,7 +29,7 @@ class BackupFileValidator(
}
if (backup.backupManga.isEmpty()) {
throw IllegalStateException(context.getString(R.string.invalid_backup_file_missing_manga))
throw IllegalStateException(context.localize(MR.strings.invalid_backup_file_missing_manga))
}
val sources = backup.backupSources.associate { it.sourceId to it.name }

View File

@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.cancelNotification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notify
import tachiyomi.core.i18n.localize
import tachiyomi.core.i18n.localizePlural
import tachiyomi.i18n.MR
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.util.concurrent.TimeUnit
@ -44,7 +47,7 @@ class BackupNotifier(private val context: Context) {
fun showBackupProgress(): NotificationCompat.Builder {
val builder = with(progressNotificationBuilder) {
setContentTitle(context.getString(R.string.creating_backup))
setContentTitle(context.localize(MR.strings.creating_backup))
setProgress(0, 0, true)
}
@ -58,7 +61,7 @@ class BackupNotifier(private val context: Context) {
context.cancelNotification(Notifications.ID_BACKUP_PROGRESS)
with(completeNotificationBuilder) {
setContentTitle(context.getString(R.string.creating_backup_error))
setContentTitle(context.localize(MR.strings.creating_backup_error))
setContentText(error)
show(Notifications.ID_BACKUP_COMPLETE)
@ -69,13 +72,13 @@ class BackupNotifier(private val context: Context) {
context.cancelNotification(Notifications.ID_BACKUP_PROGRESS)
with(completeNotificationBuilder) {
setContentTitle(context.getString(R.string.backup_created))
setContentTitle(context.localize(MR.strings.backup_created))
setContentText(unifile.filePath ?: unifile.name)
clearActions()
addAction(
R.drawable.ic_share_24dp,
context.getString(R.string.action_share),
context.localize(MR.strings.action_share),
NotificationReceiver.shareBackupPendingBroadcast(
context,
unifile.uri,
@ -89,8 +92,8 @@ class BackupNotifier(private val context: Context) {
fun showRestoreProgress(
content: String = "",
contentTitle: String = context.getString(
R.string.restoring_backup,
contentTitle: String = context.localize(
MR.strings.restoring_backup,
),
progress: Int = 0,
maxAmount: Int = 100,
@ -108,7 +111,7 @@ class BackupNotifier(private val context: Context) {
clearActions()
addAction(
R.drawable.ic_close_24dp,
context.getString(R.string.action_cancel),
context.localize(MR.strings.action_cancel),
NotificationReceiver.cancelRestorePendingBroadcast(context, Notifications.ID_RESTORE_PROGRESS),
)
}
@ -122,7 +125,7 @@ class BackupNotifier(private val context: Context) {
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
with(completeNotificationBuilder) {
setContentTitle(context.getString(R.string.restoring_backup_error))
setContentTitle(context.localize(MR.strings.restoring_backup_error))
setContentText(error)
show(Notifications.ID_RESTORE_COMPLETE)
@ -134,14 +137,14 @@ class BackupNotifier(private val context: Context) {
errorCount: Int,
path: String?,
file: String?,
contentTitle: String = context.getString(
R.string.restore_completed,
contentTitle: String = context.localize(
MR.strings.restore_completed,
),
) {
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
val timeString = context.getString(
R.string.restore_duration,
val timeString = context.localize(
MR.strings.restore_duration,
TimeUnit.MILLISECONDS.toMinutes(time),
TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MINUTES.toSeconds(
TimeUnit.MILLISECONDS.toMinutes(time),
@ -151,8 +154,8 @@ class BackupNotifier(private val context: Context) {
with(completeNotificationBuilder) {
setContentTitle(contentTitle)
setContentText(
context.resources.getQuantityString(
R.plurals.restore_completed_message,
context.localizePlural(
MR.plurals.restore_completed_message,
errorCount,
timeString,
errorCount,
@ -168,7 +171,7 @@ class BackupNotifier(private val context: Context) {
setContentIntent(errorLogIntent)
addAction(
R.drawable.ic_folder_24dp,
context.getString(R.string.action_show_errors),
context.localize(MR.strings.action_show_errors),
errorLogIntent,
)
}

View File

@ -9,14 +9,15 @@ import androidx.work.ForegroundInfo
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkerParameters
import androidx.work.workDataOf
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.system.cancelNotification
import eu.kanade.tachiyomi.util.system.isRunning
import eu.kanade.tachiyomi.util.system.workManager
import kotlinx.coroutines.CancellationException
import logcat.LogPriority
import tachiyomi.core.i18n.localize
import tachiyomi.core.util.system.logcat
import tachiyomi.i18n.MR
class BackupRestoreJob(private val context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) {
@ -40,7 +41,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
Result.success()
} catch (e: Exception) {
if (e is CancellationException) {
notifier.showRestoreError(context.getString(R.string.restoring_backup_canceled))
notifier.showRestoreError(context.localize(MR.strings.restoring_backup_canceled))
Result.success()
} else {
logcat(LogPriority.ERROR, e)

View File

@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.data.backup
import android.content.Context
import android.net.Uri
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
import eu.kanade.tachiyomi.data.backup.models.BackupFlatMetadata
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
@ -29,6 +28,7 @@ import exh.source.MERGED_SOURCE_ID
import exh.util.nullIfBlank
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.isActive
import tachiyomi.core.i18n.localize
import tachiyomi.core.preference.AndroidPreferenceStore
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.data.DatabaseHandler
@ -49,6 +49,7 @@ import tachiyomi.domain.manga.interactor.SetCustomMangaInfo
import tachiyomi.domain.manga.model.CustomMangaInfo
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.track.model.Track
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
@ -111,7 +112,7 @@ class BackupRestorer(
errors.size,
logFile.parent,
logFile.name,
contentTitle = context.getString(R.string.library_sync_complete),
contentTitle = context.localize(MR.strings.library_sync_complete),
)
} else {
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
@ -217,8 +218,8 @@ class BackupRestorer(
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.categories),
context.getString(R.string.restoring_backup),
context.localize(MR.strings.categories),
context.localize(MR.strings.restoring_backup),
)
}
@ -313,14 +314,14 @@ class BackupRestorer(
restoreProgress,
restoreAmount,
manga.title,
context.getString(R.string.syncing_library),
context.localize(MR.strings.syncing_library),
)
} else {
showRestoreProgress(
restoreProgress,
restoreAmount,
manga.title,
context.getString(R.string.restoring_backup),
context.localize(MR.strings.restoring_backup),
)
}
}
@ -821,8 +822,8 @@ class BackupRestorer(
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.app_settings),
context.getString(R.string.restoring_backup),
context.localize(MR.strings.app_settings),
context.localize(MR.strings.restoring_backup),
)
}
@ -836,8 +837,8 @@ class BackupRestorer(
showRestoreProgress(
restoreProgress,
restoreAmount,
context.getString(R.string.source_settings),
context.getString(R.string.restoring_backup),
context.localize(MR.strings.source_settings),
context.localize(MR.strings.restoring_backup),
)
}

View File

@ -14,6 +14,8 @@ import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.system.cancelNotification
import eu.kanade.tachiyomi.util.system.notificationBuilder
import eu.kanade.tachiyomi.util.system.notify
import tachiyomi.core.i18n.localize
import tachiyomi.i18n.MR
import uy.kohesive.injekt.injectLazy
import java.util.regex.Pattern
@ -78,13 +80,13 @@ internal class DownloadNotifier(private val context: Context) {
// Pause action
addAction(
R.drawable.ic_pause_24dp,
context.getString(R.string.action_pause),
context.localize(MR.strings.action_pause),
NotificationReceiver.pauseDownloadsPendingBroadcast(context),
)
}
val downloadingProgressText = context.getString(
R.string.chapter_downloading_progress,
val downloadingProgressText = context.localize(
MR.strings.chapter_downloading_progress,
download.downloadedImages,
download.pages!!.size,
)
@ -115,8 +117,8 @@ internal class DownloadNotifier(private val context: Context) {
*/
fun onPaused() {
with(progressNotificationBuilder) {
setContentTitle(context.getString(R.string.chapter_paused))
setContentText(context.getString(R.string.download_notifier_download_paused))
setContentTitle(context.localize(MR.strings.chapter_paused))
setContentText(context.localize(MR.strings.download_notifier_download_paused))
setSmallIcon(R.drawable.ic_pause_24dp)
setProgress(0, 0, false)
setOngoing(false)
@ -126,13 +128,13 @@ internal class DownloadNotifier(private val context: Context) {
// Resume action
addAction(
R.drawable.ic_play_arrow_24dp,
context.getString(R.string.action_resume),
context.localize(MR.strings.action_resume),
NotificationReceiver.resumeDownloadsPendingBroadcast(context),
)
// Clear action
addAction(
R.drawable.ic_close_24dp,
context.getString(R.string.action_cancel_all),
context.localize(MR.strings.action_cancel_all),
NotificationReceiver.clearDownloadsPendingBroadcast(context),
)
@ -162,7 +164,7 @@ internal class DownloadNotifier(private val context: Context) {
*/
fun onWarning(reason: String, timeout: Long? = null, contentIntent: PendingIntent? = null) {
with(errorNotificationBuilder) {
setContentTitle(context.getString(R.string.download_notifier_downloader_title))
setContentTitle(context.localize(MR.strings.download_notifier_downloader_title))
setStyle(NotificationCompat.BigTextStyle().bigText(reason))
setSmallIcon(R.drawable.ic_warning_white_24dp)
setAutoCancel(true)
@ -190,9 +192,9 @@ internal class DownloadNotifier(private val context: Context) {
// Create notification
with(errorNotificationBuilder) {
setContentTitle(
mangaTitle?.plus(": $chapter") ?: context.getString(R.string.download_notifier_downloader_title),
mangaTitle?.plus(": $chapter") ?: context.localize(MR.strings.download_notifier_downloader_title),
)
setContentText(error ?: context.getString(R.string.download_notifier_unknown_error))
setContentText(error ?: context.localize(MR.strings.download_notifier_unknown_error))
setSmallIcon(R.drawable.ic_warning_white_24dp)
clearActions()
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))

View File

@ -3,17 +3,18 @@ package eu.kanade.tachiyomi.data.download
import android.content.Context
import androidx.core.net.toUri
import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.util.storage.DiskUtil
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import logcat.LogPriority
import tachiyomi.core.i18n.localize
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.chapter.model.Chapter
import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.domain.manga.model.Manga
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -58,7 +59,7 @@ class DownloadProvider(
.createDirectory(getMangaDirName(mangaTitle))
} catch (e: Throwable) {
logcat(LogPriority.ERROR, e) { "Invalid download directory" }
throw Exception(context.getString(R.string.invalid_location, downloadsDir))
throw Exception(context.localize(MR.strings.invalid_location, downloadsDir))
}
}

View File

@ -6,9 +6,8 @@ import android.content.Context
import android.content.Intent
import android.os.IBinder
import android.os.PowerManager
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import eu.kanade.tachiyomi.R
import dev.icerock.moko.resources.StringResource
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.system.acquireWakeLock
import eu.kanade.tachiyomi.util.system.isConnectedToWifi
@ -27,9 +26,11 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import logcat.LogPriority
import ru.beryukhov.reactivenetwork.ReactiveNetwork
import tachiyomi.core.i18n.localize
import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.i18n.MR
import uy.kohesive.injekt.injectLazy
/**
@ -111,8 +112,8 @@ class DownloadService : Service() {
return null
}
private fun downloaderStop(@StringRes string: Int) {
downloadManager.downloaderStop(getString(string))
private fun downloaderStop(string: StringResource) {
downloadManager.downloaderStop(localize(string))
}
private fun listenNetworkChanges() {
@ -122,20 +123,20 @@ class DownloadService : Service() {
withUIContext {
if (isOnline()) {
if (downloadPreferences.downloadOnlyOverWifi().get() && !isConnectedToWifi()) {
downloaderStop(R.string.download_notifier_text_only_wifi)
downloaderStop(MR.strings.download_notifier_text_only_wifi)
} else {
val started = downloadManager.downloaderStart()
if (!started) stopSelf()
}
} else {
downloaderStop(R.string.download_notifier_no_network)
downloaderStop(MR.strings.download_notifier_no_network)
}
}
}
.catch { error ->
withUIContext {
logcat(LogPriority.ERROR, error)
toast(R.string.download_queue_error)
toast(MR.strings.download_queue_error)
stopSelf()
}
}
@ -144,7 +145,7 @@ class DownloadService : Service() {
private fun getPlaceholderNotification(): Notification {
return notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
setContentTitle(getString(R.string.download_notifier_downloader_title))
setContentTitle(localize(MR.strings.download_notifier_downloader_title))
}.build()
}
}

View File

@ -0,0 +1,210 @@
package eu.kanade.tachiyomi.data.library
import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.ExistingWorkPolicy
import androidx.work.ForegroundInfo
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkQuery
import androidx.work.WorkerParameters
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.copyFrom
import eu.kanade.domain.manga.model.toSManga
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.source.UnmeteredSource
import eu.kanade.tachiyomi.util.prepUpdateCover
import eu.kanade.tachiyomi.util.system.isRunning
import eu.kanade.tachiyomi.util.system.workManager
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import logcat.LogPriority
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.interactor.GetLibraryManga
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.toMangaUpdate
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicInteger
class MetadataUpdateJob(private val context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) {
private val sourceManager: SourceManager = Injekt.get()
private val coverCache: CoverCache = Injekt.get()
private val getLibraryManga: GetLibraryManga = Injekt.get()
private val updateManga: UpdateManga = Injekt.get()
private val notifier = LibraryUpdateNotifier(context)
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
override suspend fun doWork(): Result {
try {
setForeground(getForegroundInfo())
} catch (e: IllegalStateException) {
logcat(LogPriority.ERROR, e) { "Not allowed to set foreground job" }
}
addMangaToQueue()
return withIOContext {
try {
updateMetadata()
Result.success()
} catch (e: Exception) {
if (e is CancellationException) {
// Assume success although cancelled
Result.success()
} else {
logcat(LogPriority.ERROR, e)
Result.failure()
}
} finally {
notifier.cancelProgressNotification()
}
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
val notifier = LibraryUpdateNotifier(context)
return ForegroundInfo(
Notifications.ID_LIBRARY_PROGRESS,
notifier.progressNotificationBuilder.build(),
)
}
/**
* Adds list of manga to be updated.
*/
private fun addMangaToQueue() {
mangaToUpdate = runBlocking { getLibraryManga.await() }
// Warn when excessively checking a single source
val maxUpdatesFromSource = mangaToUpdate
.groupBy { it.manga.source }
.filterKeys { sourceManager.get(it) !is UnmeteredSource }
.maxOfOrNull { it.value.size } ?: 0
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
notifier.showQueueSizeWarningNotification()
}
}
private suspend fun updateMetadata() {
val semaphore = Semaphore(5)
val progressCount = AtomicInteger(0)
val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
coroutineScope {
mangaToUpdate.groupBy { it.manga.source }
.values
.map { mangaInSource ->
async {
semaphore.withPermit {
mangaInSource.forEach { libraryManga ->
val manga = libraryManga.manga
ensureActive()
withUpdateNotification(
currentlyUpdatingManga,
progressCount,
manga,
) {
val source = sourceManager.get(manga.source) ?: return@withUpdateNotification
try {
val networkManga = source.getMangaDetails(manga.toSManga())
val updatedManga = manga.prepUpdateCover(coverCache, networkManga, true)
.copyFrom(networkManga)
try {
updateManga.await(updatedManga.toMangaUpdate())
} catch (e: Exception) {
logcat(LogPriority.ERROR) { "Manga doesn't exist anymore" }
}
} catch (e: Throwable) {
// Ignore errors and continue
logcat(LogPriority.ERROR, e)
}
}
}
}
}
}
.awaitAll()
}
notifier.cancelProgressNotification()
}
private suspend fun withUpdateNotification(
updatingManga: CopyOnWriteArrayList<Manga>,
completed: AtomicInteger,
manga: Manga,
block: suspend () -> Unit,
) = coroutineScope {
ensureActive()
updatingManga.add(manga)
notifier.showProgressNotification(
updatingManga,
completed.get(),
mangaToUpdate.size,
)
block()
ensureActive()
updatingManga.remove(manga)
completed.getAndIncrement()
notifier.showProgressNotification(
updatingManga,
completed.get(),
mangaToUpdate.size,
)
}
companion object {
private const val TAG = "MetadataUpdate"
private const val WORK_NAME_MANUAL = "MetadataUpdate"
private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60
fun startNow(context: Context): Boolean {
val wm = context.workManager
if (wm.isRunning(TAG)) {
// Already running either as a scheduled or manual job
return false
}
val request = OneTimeWorkRequestBuilder<MetadataUpdateJob>()
.addTag(TAG)
.addTag(WORK_NAME_MANUAL)
.build()
wm.enqueueUniqueWork(WORK_NAME_MANUAL, ExistingWorkPolicy.KEEP, request)
return true
}
fun stop(context: Context) {
val wm = context.workManager
val workQuery = WorkQuery.Builder.fromTags(listOf(TAG))
.addStates(listOf(WorkInfo.State.RUNNING))
.build()
wm.getWorkInfos(workQuery).get()
// Should only return one work but just in case
.forEach {
wm.cancelWorkById(it.id)
}
}
}
}

View File

@ -7,7 +7,6 @@ import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.core.net.toUri
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
@ -32,6 +31,7 @@ import tachiyomi.domain.download.service.DownloadPreferences
import tachiyomi.domain.manga.interactor.GetManga
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
@ -173,7 +173,7 @@ class NotificationReceiver : BroadcastReceiver() {
}
context.startActivity(intent)
} else {
context.toast(R.string.chapter_error)
context.toast(MR.strings.chapter_error)
}
}

View File

@ -5,9 +5,10 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_DEFAULT
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_HIGH
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_LOW
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.buildNotificationChannel
import eu.kanade.tachiyomi.util.system.buildNotificationChannelGroup
import tachiyomi.core.i18n.localize
import tachiyomi.i18n.MR
/**
* Class to manage the basic information of all the notifications used in the app.
@ -102,16 +103,16 @@ object Notifications {
notificationManager.createNotificationChannelGroupsCompat(
listOf(
buildNotificationChannelGroup(GROUP_BACKUP_RESTORE) {
setName(context.getString(R.string.label_backup))
setName(context.localize(MR.strings.label_backup))
},
buildNotificationChannelGroup(GROUP_DOWNLOADER) {
setName(context.getString(R.string.download_notifier_downloader_title))
setName(context.localize(MR.strings.download_notifier_downloader_title))
},
buildNotificationChannelGroup(GROUP_LIBRARY) {
setName(context.getString(R.string.label_library))
setName(context.localize(MR.strings.label_library))
},
buildNotificationChannelGroup(GROUP_APK_UPDATES) {
setName(context.getString(R.string.label_recent_updates))
setName(context.localize(MR.strings.label_recent_updates))
},
),
)
@ -119,57 +120,57 @@ object Notifications {
notificationManager.createNotificationChannelsCompat(
listOf(
buildNotificationChannel(CHANNEL_COMMON, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_common))
setName(context.localize(MR.strings.channel_common))
},
buildNotificationChannel(CHANNEL_LIBRARY_PROGRESS, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_progress))
setName(context.localize(MR.strings.channel_progress))
setGroup(GROUP_LIBRARY)
setShowBadge(false)
},
buildNotificationChannel(CHANNEL_LIBRARY_ERROR, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_errors))
setName(context.localize(MR.strings.channel_errors))
setGroup(GROUP_LIBRARY)
setShowBadge(false)
},
buildNotificationChannel(CHANNEL_LIBRARY_SKIPPED, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_skipped))
setName(context.localize(MR.strings.channel_skipped))
setGroup(GROUP_LIBRARY)
setShowBadge(false)
},
buildNotificationChannel(CHANNEL_NEW_CHAPTERS, IMPORTANCE_DEFAULT) {
setName(context.getString(R.string.channel_new_chapters))
setName(context.localize(MR.strings.channel_new_chapters))
},
buildNotificationChannel(CHANNEL_DOWNLOADER_PROGRESS, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_progress))
setName(context.localize(MR.strings.channel_progress))
setGroup(GROUP_DOWNLOADER)
setShowBadge(false)
},
buildNotificationChannel(CHANNEL_DOWNLOADER_ERROR, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_errors))
setName(context.localize(MR.strings.channel_errors))
setGroup(GROUP_DOWNLOADER)
setShowBadge(false)
},
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_PROGRESS, IMPORTANCE_LOW) {
setName(context.getString(R.string.channel_progress))
setName(context.localize(MR.strings.channel_progress))
setGroup(GROUP_BACKUP_RESTORE)
setShowBadge(false)
},
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_COMPLETE, IMPORTANCE_HIGH) {
setName(context.getString(R.string.channel_complete))
setName(context.localize(MR.strings.channel_complete))
setGroup(GROUP_BACKUP_RESTORE)
setShowBadge(false)
setSound(null, null)
},
buildNotificationChannel(CHANNEL_INCOGNITO_MODE, IMPORTANCE_LOW) {
setName(context.getString(R.string.pref_incognito_mode))
setName(context.localize(MR.strings.pref_incognito_mode))
},
buildNotificationChannel(CHANNEL_APP_UPDATE, IMPORTANCE_DEFAULT) {
setGroup(GROUP_APK_UPDATES)
setName(context.getString(R.string.channel_app_updates))
setName(context.localize(MR.strings.channel_app_updates))
},
buildNotificationChannel(CHANNEL_EXTENSIONS_UPDATE, IMPORTANCE_DEFAULT) {
setGroup(GROUP_APK_UPDATES)
setName(context.getString(R.string.channel_ext_updates))
setName(context.localize(MR.strings.channel_ext_updates))
},
),
)

Some files were not shown because too many files have changed in this diff Show More