From c283abefb03f79ce6652492db71cde410f828f78 Mon Sep 17 00:00:00 2001 From: sdaqo Date: Sun, 12 Jan 2025 04:38:05 +0100 Subject: [PATCH] Add option to enable incognito mode per extension (#157) * add per Extension Incognito Mode * migrate incognito sources when extension is updated * remove incognito sources when extension is uninstalled * remove not used variable * address change requests address change requests * Rebase and cleanup code --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- CHANGELOG.md | 1 + .../java/eu/kanade/domain/DomainModule.kt | 4 ++ .../source/interactor/GetIncognitoState.kt | 35 ++++++++++++++++ .../source/interactor/ToggleIncognito.kt | 14 +++++++ .../source/service/SourcePreferences.kt | 2 + .../browse/ExtensionDetailsScreen.kt | 42 +++++++++++++++---- .../tachiyomi/extension/ExtensionManager.kt | 23 +++++++--- .../details/ExtensionDetailsScreen.kt | 1 + .../details/ExtensionDetailsScreenModel.kt | 21 ++++++++++ .../source/browse/BrowseSourceScreen.kt | 2 +- .../source/browse/BrowseSourceScreenModel.kt | 6 +-- .../kanade/tachiyomi/ui/main/MainActivity.kt | 10 ++++- .../tachiyomi/ui/reader/ReaderViewModel.kt | 5 ++- .../moko-resources/base/strings.xml | 1 + 14 files changed, 146 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/eu/kanade/domain/source/interactor/GetIncognitoState.kt create mode 100644 app/src/main/java/eu/kanade/domain/source/interactor/ToggleIncognito.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index d90774449..6bba18064 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ The format is a modified version of [Keep a Changelog](https://keepachangelog.co ## [Unreleased] ### Added - Add option to always decode long strip images with SSIV +- Added option to enable incognito per extension ([@sdaqo](https://github.com/sdaqo), [@AntsyLich](https://github.com/AntsyLich)) ([#157](https://github.com/mihonapp/mihon/pull/157)) ### Fixed - Fix MAL `main_picture` nullability breaking search if a result doesn't have a cover set ([@MajorTanya](https://github.com/MajorTanya)) ([#1618](https://github.com/mihonapp/mihon/pull/1618)) diff --git a/app/src/main/java/eu/kanade/domain/DomainModule.kt b/app/src/main/java/eu/kanade/domain/DomainModule.kt index 08787e1f8..266ff82db 100644 --- a/app/src/main/java/eu/kanade/domain/DomainModule.kt +++ b/app/src/main/java/eu/kanade/domain/DomainModule.kt @@ -13,9 +13,11 @@ import eu.kanade.domain.manga.interactor.SetExcludedScanlators import eu.kanade.domain.manga.interactor.SetMangaViewerFlags import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.source.interactor.GetEnabledSources +import eu.kanade.domain.source.interactor.GetIncognitoState import eu.kanade.domain.source.interactor.GetLanguagesWithSources import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount import eu.kanade.domain.source.interactor.SetMigrateSorting +import eu.kanade.domain.source.interactor.ToggleIncognito import eu.kanade.domain.source.interactor.ToggleLanguage import eu.kanade.domain.source.interactor.ToggleSource import eu.kanade.domain.source.interactor.ToggleSourcePin @@ -191,5 +193,7 @@ class DomainModule : InjektModule { addFactory { DeleteExtensionRepo(get()) } addFactory { ReplaceExtensionRepo(get()) } addFactory { UpdateExtensionRepo(get(), get()) } + addFactory { ToggleIncognito(get()) } + addFactory { GetIncognitoState(get(), get(), get()) } } } diff --git a/app/src/main/java/eu/kanade/domain/source/interactor/GetIncognitoState.kt b/app/src/main/java/eu/kanade/domain/source/interactor/GetIncognitoState.kt new file mode 100644 index 000000000..41ab65f30 --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/source/interactor/GetIncognitoState.kt @@ -0,0 +1,35 @@ +package eu.kanade.domain.source.interactor + +import eu.kanade.domain.base.BasePreferences +import eu.kanade.domain.source.service.SourcePreferences +import eu.kanade.tachiyomi.extension.ExtensionManager +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged + +class GetIncognitoState( + private val basePreferences: BasePreferences, + private val sourcePreferences: SourcePreferences, + private val extensionManager: ExtensionManager, +) { + fun await(sourceId: Long?): Boolean { + if (basePreferences.incognitoMode().get()) return true + if (sourceId == null) return false + val extensionPackage = extensionManager.getExtensionPackage(sourceId) ?: return false + + return extensionPackage in sourcePreferences.incognitoExtensions().get() + } + + fun subscribe(sourceId: Long?): Flow { + if (sourceId == null) return basePreferences.incognitoMode().changes() + + return combine( + basePreferences.incognitoMode().changes(), + sourcePreferences.incognitoExtensions().changes(), + extensionManager.getExtensionPackageAsFlow(sourceId), + ) { incognito, incognitoExtensions, extensionPackage -> + incognito || (extensionPackage in incognitoExtensions) + } + .distinctUntilChanged() + } +} diff --git a/app/src/main/java/eu/kanade/domain/source/interactor/ToggleIncognito.kt b/app/src/main/java/eu/kanade/domain/source/interactor/ToggleIncognito.kt new file mode 100644 index 000000000..ccd13bf6a --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/source/interactor/ToggleIncognito.kt @@ -0,0 +1,14 @@ +package eu.kanade.domain.source.interactor + +import eu.kanade.domain.source.service.SourcePreferences +import tachiyomi.core.common.preference.getAndSet + +class ToggleIncognito( + private val preferences: SourcePreferences, +) { + fun await(extensions: String, enable: Boolean) { + preferences.incognitoExtensions().getAndSet { + if (enable) it.plus(extensions) else it.minus(extensions) + } + } +} diff --git a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt index 72989891e..baae91d68 100644 --- a/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt +++ b/app/src/main/java/eu/kanade/domain/source/service/SourcePreferences.kt @@ -22,6 +22,8 @@ class SourcePreferences( fun disabledSources() = preferenceStore.getStringSet("hidden_catalogues", emptySet()) + fun incognitoExtensions() = preferenceStore.getStringSet("incognito_extensions", emptySet()) + fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet()) fun lastUsedSource() = preferenceStore.getLong( diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt index 501c0b6fd..c2219c395 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt @@ -35,8 +35,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -48,6 +50,7 @@ import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget import eu.kanade.presentation.more.settings.widget.TrailingWidgetBuffer +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreenModel @@ -72,6 +75,7 @@ fun ExtensionDetailsScreen( onClickClearCookies: () -> Unit, onClickUninstall: () -> Unit, onClickSource: (sourceId: Long) -> Unit, + onClickIncognito: (Boolean) -> Unit, ) { val uriHandler = LocalUriHandler.current val url = remember(state.extension) { @@ -140,9 +144,11 @@ fun ExtensionDetailsScreen( contentPadding = paddingValues, extension = state.extension, sources = state.sources, + incognitoMode = state.isIncognito, onClickSourcePreferences = onClickSourcePreferences, onClickUninstall = onClickUninstall, onClickSource = onClickSource, + onClickIncognito = onClickIncognito, ) } } @@ -152,9 +158,11 @@ private fun ExtensionDetails( contentPadding: PaddingValues, extension: Extension.Installed, sources: ImmutableList, + incognitoMode: Boolean, onClickSourcePreferences: (sourceId: Long) -> Unit, onClickUninstall: () -> Unit, onClickSource: (sourceId: Long) -> Unit, + onClickIncognito: (Boolean) -> Unit, ) { val context = LocalContext.current var showNsfwWarning by remember { mutableStateOf(false) } @@ -171,6 +179,7 @@ private fun ExtensionDetails( item { DetailsHeader( extension = extension, + extIncognitoMode = incognitoMode, onClickUninstall = onClickUninstall, onClickAppInfo = { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { @@ -182,6 +191,7 @@ private fun ExtensionDetails( onClickAgeRating = { showNsfwWarning = true }, + onExtIncognitoChange = onClickIncognito, ) } @@ -209,9 +219,11 @@ private fun ExtensionDetails( @Composable private fun DetailsHeader( extension: Extension, + extIncognitoMode: Boolean, onClickAgeRating: () -> Unit, onClickUninstall: () -> Unit, onClickAppInfo: (() -> Unit)?, + onExtIncognitoChange: (Boolean) -> Unit, ) { val context = LocalContext.current @@ -219,9 +231,8 @@ private fun DetailsHeader( Column( modifier = Modifier .fillMaxWidth() + .padding(horizontal = MaterialTheme.padding.medium) .padding( - start = MaterialTheme.padding.medium, - end = MaterialTheme.padding.medium, top = MaterialTheme.padding.medium, bottom = MaterialTheme.padding.small, ) @@ -313,12 +324,9 @@ private fun DetailsHeader( } Row( - modifier = Modifier.padding( - start = MaterialTheme.padding.medium, - end = MaterialTheme.padding.medium, - top = MaterialTheme.padding.small, - bottom = MaterialTheme.padding.medium, - ), + modifier = Modifier + .padding(horizontal = MaterialTheme.padding.medium) + .padding(top = MaterialTheme.padding.small), horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium), ) { OutlinedButton( @@ -341,6 +349,24 @@ private fun DetailsHeader( } } + TextPreferenceWidget( + modifier = Modifier.padding(horizontal = MaterialTheme.padding.small), + title = stringResource(MR.strings.pref_incognito_mode), + subtitle = stringResource(MR.strings.pref_incognito_mode_extension_summary), + icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp), + widget = { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Switch( + checked = extIncognitoMode, + onCheckedChange = onExtIncognitoChange, + modifier = Modifier.padding(start = TrailingWidgetBuffer), + ) + } + }, + ) + HorizontalDivider() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index 65c5454cd..a08b004a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -78,13 +78,24 @@ class ExtensionManager( private var subLanguagesEnabledOnFirstRun = preferences.enabledLanguages().isSet() - fun getAppIconForSource(sourceId: Long): Drawable? { - val pkgName = installedExtensionMapFlow.value.values - .find { ext -> - ext.sources.any { it.id == sourceId } - } + fun getExtensionPackage(sourceId: Long): String? { + return installedExtensionsFlow.value.find { extension -> + extension.sources.any { it.id == sourceId } + } ?.pkgName - ?: return null + } + + fun getExtensionPackageAsFlow(sourceId: Long): Flow { + return installedExtensionsFlow.map { extensions -> + extensions.find { extension -> + extension.sources.any { it.id == sourceId } + } + ?.pkgName + } + } + + fun getAppIconForSource(sourceId: Long): Drawable? { + val pkgName = getExtensionPackage(sourceId) ?: return null return iconMap[pkgName] ?: iconMap.getOrPut(pkgName) { ExtensionLoader.getExtensionPackageInfoFromPkgName(context, pkgName)!!.applicationInfo!! diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreen.kt index 4a4a78cde..8cac9c5cc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreen.kt @@ -39,6 +39,7 @@ data class ExtensionDetailsScreen( onClickClearCookies = screenModel::clearCookies, onClickUninstall = screenModel::uninstallExtension, onClickSource = screenModel::toggleSource, + onClickIncognito = screenModel::toggleIncognito, ) LaunchedEffect(Unit) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt index 4266c4730..7997f7262 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/details/ExtensionDetailsScreenModel.kt @@ -6,7 +6,9 @@ import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.domain.extension.interactor.ExtensionSourceItem import eu.kanade.domain.extension.interactor.GetExtensionSources +import eu.kanade.domain.source.interactor.ToggleIncognito import eu.kanade.domain.source.interactor.ToggleSource +import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.network.NetworkHelper @@ -19,6 +21,7 @@ import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.update @@ -36,6 +39,8 @@ class ExtensionDetailsScreenModel( private val extensionManager: ExtensionManager = Injekt.get(), private val getExtensionSources: GetExtensionSources = Injekt.get(), private val toggleSource: ToggleSource = Injekt.get(), + private val toggleIncognito: ToggleIncognito = Injekt.get(), + private val preferences: SourcePreferences = Injekt.get(), ) : StateScreenModel(State()) { private val _events: Channel = Channel() @@ -80,6 +85,15 @@ class ExtensionDetailsScreenModel( } } } + launch { + preferences.incognitoExtensions() + .changes() + .map { pkgName in it } + .distinctUntilChanged() + .collectLatest { isIncognito -> + mutableState.update { it.copy(isIncognito = isIncognito) } + } + } } } @@ -118,9 +132,16 @@ class ExtensionDetailsScreenModel( ?.let { toggleSource.await(it, enable) } } + fun toggleIncognito(enable: Boolean) { + state.value.extension?.pkgName?.let { packageName -> + toggleIncognito.await(packageName, enable) + } + } + @Immutable data class State( val extension: Extension.Installed? = null, + val isIncognito: Boolean = false, private val _sources: ImmutableList? = null, ) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt index af517409f..f4c6fb98b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreen.kt @@ -67,7 +67,7 @@ import tachiyomi.presentation.core.screens.LoadingScreen import tachiyomi.source.local.LocalSource data class BrowseSourceScreen( - private val sourceId: Long, + val sourceId: Long, private val listingQuery: String?, ) : Screen(), AssistContentScreen { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt index dff062503..e3da069fb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt @@ -14,9 +14,9 @@ import androidx.paging.map import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.screenModelScope import eu.kanade.core.preference.asState -import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.manga.interactor.UpdateManga import eu.kanade.domain.manga.model.toDomainManga +import eu.kanade.domain.source.interactor.GetIncognitoState import eu.kanade.domain.source.service.SourcePreferences import eu.kanade.domain.track.interactor.AddTracks import eu.kanade.presentation.util.ioCoroutineScope @@ -60,7 +60,6 @@ class BrowseSourceScreenModel( listingQuery: String?, sourceManager: SourceManager = Injekt.get(), sourcePreferences: SourcePreferences = Injekt.get(), - basePreferences: BasePreferences = Injekt.get(), private val libraryPreferences: LibraryPreferences = Injekt.get(), private val coverCache: CoverCache = Injekt.get(), private val getRemoteManga: GetRemoteManga = Injekt.get(), @@ -72,6 +71,7 @@ class BrowseSourceScreenModel( private val networkToLocalManga: NetworkToLocalManga = Injekt.get(), private val updateManga: UpdateManga = Injekt.get(), private val addTracks: AddTracks = Injekt.get(), + private val getIncognitoState: GetIncognitoState = Injekt.get(), ) : StateScreenModel(State(Listing.valueOf(listingQuery))) { var displayMode by sourcePreferences.sourceDisplayMode().asState(screenModelScope) @@ -97,7 +97,7 @@ class BrowseSourceScreenModel( } } - if (!basePreferences.incognitoMode().get()) { + if (!getIncognitoState.await(source.id)) { sourcePreferences.lastUsedSource().set(source.id) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index aefe0fe77..f94a96e5d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -54,6 +54,7 @@ import cafe.adriel.voyager.navigator.Navigator import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.domain.base.BasePreferences +import eu.kanade.domain.source.interactor.GetIncognitoState import eu.kanade.presentation.components.AppStateBanners import eu.kanade.presentation.components.DownloadedOnlyBannerBackgroundColor import eu.kanade.presentation.components.IncognitoModeBannerBackgroundColor @@ -110,6 +111,8 @@ class MainActivity : BaseActivity() { private val downloadCache: DownloadCache by injectLazy() private val chapterCache: ChapterCache by injectLazy() + private val getIncognitoState: GetIncognitoState by injectLazy() + // To be checked by splash screen. If true then splash screen will be removed. var ready = false @@ -138,7 +141,7 @@ class MainActivity : BaseActivity() { setComposeContent { val context = LocalContext.current - val incognito by preferences.incognitoMode().collectAsState() + var incognito by remember { mutableStateOf(getIncognitoState.await(null)) } val downloadOnly by preferences.downloadedOnly().collectAsState() val indexing by downloadCache.isInitializing.collectAsState() @@ -174,6 +177,11 @@ class MainActivity : BaseActivity() { preferences.incognitoMode().set(false) } } + LaunchedEffect(navigator.lastItem) { + (navigator.lastItem as? BrowseSourceScreen)?.sourceId + .let(getIncognitoState::subscribe) + .collectLatest { incognito = it } + } val scaffoldInsets = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal) Scaffold( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index f633bdbad..40c9e8297 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -12,6 +12,7 @@ import eu.kanade.domain.chapter.model.toDbChapter import eu.kanade.domain.manga.interactor.SetMangaViewerFlags import eu.kanade.domain.manga.model.readerOrientation import eu.kanade.domain.manga.model.readingMode +import eu.kanade.domain.source.interactor.GetIncognitoState import eu.kanade.domain.track.interactor.TrackChapter import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.toDomainChapter @@ -87,7 +88,6 @@ class ReaderViewModel @JvmOverloads constructor( private val downloadManager: DownloadManager = Injekt.get(), private val downloadProvider: DownloadProvider = Injekt.get(), private val imageSaver: ImageSaver = Injekt.get(), - preferences: BasePreferences = Injekt.get(), val readerPreferences: ReaderPreferences = Injekt.get(), private val basePreferences: BasePreferences = Injekt.get(), private val downloadPreferences: DownloadPreferences = Injekt.get(), @@ -99,6 +99,7 @@ class ReaderViewModel @JvmOverloads constructor( private val upsertHistory: UpsertHistory = Injekt.get(), private val updateChapter: UpdateChapter = Injekt.get(), private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(), + private val getIncognitoState: GetIncognitoState = Injekt.get(), ) : ViewModel() { private val mutableState = MutableStateFlow(State()) @@ -216,7 +217,7 @@ class ReaderViewModel @JvmOverloads constructor( .map(::ReaderChapter) } - private val incognitoMode = preferences.incognitoMode().get() + private val incognitoMode: Boolean by lazy { getIncognitoState.await(manga?.source) } private val downloadAheadAmount = downloadPreferences.autoDownloadWhileReading().get() init { diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 05b72f4e5..5ad98d60b 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -637,6 +637,7 @@ Downloaded only Incognito mode Pauses reading history + Pause reading history for extension Disable incognito mode Filters all entries in your library