Support external repos
Largely taken from SY. Co-authored-by: jobobby04 <jobobby04@users.noreply.github.com> (cherry picked from commit c17ada2c98041877ab901efb9b03497130ead34a) # Conflicts: # app/src/main/java/eu/kanade/domain/source/interactor/CreateSourceRepo.kt # app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt # app/src/main/java/eu/kanade/presentation/category/SourceRepoScreen.kt # app/src/main/java/eu/kanade/presentation/category/components/CategoryDialogs.kt # app/src/main/java/eu/kanade/presentation/category/components/repo/SourceRepoContent.kt # app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt # app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt # app/src/main/java/eu/kanade/tachiyomi/extension/model/Extension.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryScreen.kt # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt
This commit is contained in:
parent
b677f81fb1
commit
24a56a5529
@ -11,8 +11,11 @@ import eu.kanade.domain.manga.interactor.GetExcludedScanlators
|
|||||||
import eu.kanade.domain.manga.interactor.SetExcludedScanlators
|
import eu.kanade.domain.manga.interactor.SetExcludedScanlators
|
||||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
||||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||||
|
import eu.kanade.domain.source.interactor.CreateSourceRepo
|
||||||
|
import eu.kanade.domain.source.interactor.DeleteSourceRepos
|
||||||
import eu.kanade.domain.source.interactor.GetEnabledSources
|
import eu.kanade.domain.source.interactor.GetEnabledSources
|
||||||
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
import eu.kanade.domain.source.interactor.GetLanguagesWithSources
|
||||||
|
import eu.kanade.domain.source.interactor.GetSourceRepos
|
||||||
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
|
||||||
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
import eu.kanade.domain.source.interactor.SetMigrateSorting
|
||||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||||
@ -167,5 +170,9 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { ToggleLanguage(get()) }
|
addFactory { ToggleLanguage(get()) }
|
||||||
addFactory { ToggleSource(get()) }
|
addFactory { ToggleSource(get()) }
|
||||||
addFactory { ToggleSourcePin(get()) }
|
addFactory { ToggleSourcePin(get()) }
|
||||||
|
|
||||||
|
addFactory { CreateSourceRepo(get()) }
|
||||||
|
addFactory { DeleteSourceRepos(get()) }
|
||||||
|
addFactory { GetSourceRepos(get()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import eu.kanade.domain.manga.interactor.GetPagePreviews
|
|||||||
import eu.kanade.domain.manga.interactor.GetSortTag
|
import eu.kanade.domain.manga.interactor.GetSortTag
|
||||||
import eu.kanade.domain.manga.interactor.ReorderSortTag
|
import eu.kanade.domain.manga.interactor.ReorderSortTag
|
||||||
import eu.kanade.domain.source.interactor.CreateSourceCategory
|
import eu.kanade.domain.source.interactor.CreateSourceCategory
|
||||||
import eu.kanade.domain.source.interactor.CreateSourceRepo
|
|
||||||
import eu.kanade.domain.source.interactor.DeleteSourceCategory
|
import eu.kanade.domain.source.interactor.DeleteSourceCategory
|
||||||
import eu.kanade.domain.source.interactor.GetExhSavedSearch
|
import eu.kanade.domain.source.interactor.GetExhSavedSearch
|
||||||
import eu.kanade.domain.source.interactor.GetShowLatest
|
import eu.kanade.domain.source.interactor.GetShowLatest
|
||||||
@ -61,14 +60,12 @@ import tachiyomi.domain.source.interactor.CountFeedSavedSearchBySourceId
|
|||||||
import tachiyomi.domain.source.interactor.CountFeedSavedSearchGlobal
|
import tachiyomi.domain.source.interactor.CountFeedSavedSearchGlobal
|
||||||
import tachiyomi.domain.source.interactor.DeleteFeedSavedSearchById
|
import tachiyomi.domain.source.interactor.DeleteFeedSavedSearchById
|
||||||
import tachiyomi.domain.source.interactor.DeleteSavedSearchById
|
import tachiyomi.domain.source.interactor.DeleteSavedSearchById
|
||||||
import tachiyomi.domain.source.interactor.DeleteSourceRepos
|
|
||||||
import tachiyomi.domain.source.interactor.GetFeedSavedSearchBySourceId
|
import tachiyomi.domain.source.interactor.GetFeedSavedSearchBySourceId
|
||||||
import tachiyomi.domain.source.interactor.GetFeedSavedSearchGlobal
|
import tachiyomi.domain.source.interactor.GetFeedSavedSearchGlobal
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchById
|
import tachiyomi.domain.source.interactor.GetSavedSearchById
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceId
|
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceId
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceIdFeed
|
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceIdFeed
|
||||||
import tachiyomi.domain.source.interactor.GetSavedSearchGlobalFeed
|
import tachiyomi.domain.source.interactor.GetSavedSearchGlobalFeed
|
||||||
import tachiyomi.domain.source.interactor.GetSourceRepos
|
|
||||||
import tachiyomi.domain.source.interactor.InsertFeedSavedSearch
|
import tachiyomi.domain.source.interactor.InsertFeedSavedSearch
|
||||||
import tachiyomi.domain.source.interactor.InsertSavedSearch
|
import tachiyomi.domain.source.interactor.InsertSavedSearch
|
||||||
import tachiyomi.domain.source.repository.FeedSavedSearchRepository
|
import tachiyomi.domain.source.repository.FeedSavedSearchRepository
|
||||||
@ -94,9 +91,6 @@ class SYDomainModule : InjektModule {
|
|||||||
addFactory { FilterSerializer() }
|
addFactory { FilterSerializer() }
|
||||||
addFactory { GetHistoryByMangaId(get()) }
|
addFactory { GetHistoryByMangaId(get()) }
|
||||||
addFactory { GetChapterByUrl(get()) }
|
addFactory { GetChapterByUrl(get()) }
|
||||||
addFactory { CreateSourceRepo(get()) }
|
|
||||||
addFactory { DeleteSourceRepos(get()) }
|
|
||||||
addFactory { GetSourceRepos(get()) }
|
|
||||||
addFactory { GetSourceCategories(get()) }
|
addFactory { GetSourceCategories(get()) }
|
||||||
addFactory { CreateSourceCategory(get()) }
|
addFactory { CreateSourceCategory(get()) }
|
||||||
addFactory { RenameSourceCategory(get(), get()) }
|
addFactory { RenameSourceCategory(get(), get()) }
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package eu.kanade.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import tachiyomi.core.preference.plusAssign
|
import tachiyomi.core.preference.plusAssign
|
||||||
import tachiyomi.domain.UnsortedPreferences
|
|
||||||
|
|
||||||
class CreateSourceRepo(private val preferences: UnsortedPreferences) {
|
class CreateSourceRepo(private val preferences: SourcePreferences) {
|
||||||
|
|
||||||
fun await(name: String): Result {
|
fun await(name: String): Result {
|
||||||
// Do not allow invalid formats
|
// Do not allow invalid formats
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package tachiyomi.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
import tachiyomi.domain.UnsortedPreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
|
|
||||||
class DeleteSourceRepos(private val preferences: UnsortedPreferences) {
|
class DeleteSourceRepos(private val preferences: SourcePreferences) {
|
||||||
|
|
||||||
fun await(repos: List<String>) {
|
fun await(repos: List<String>) {
|
||||||
preferences.extensionRepos().set(
|
preferences.extensionRepos().set(
|
@ -1,10 +1,10 @@
|
|||||||
package tachiyomi.domain.source.interactor
|
package eu.kanade.domain.source.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import tachiyomi.domain.UnsortedPreferences
|
|
||||||
|
|
||||||
class GetSourceRepos(private val preferences: UnsortedPreferences) {
|
class GetSourceRepos(private val preferences: SourcePreferences) {
|
||||||
|
|
||||||
fun subscribe(): Flow<List<String>> {
|
fun subscribe(): Flow<List<String>> {
|
||||||
return preferences.extensionRepos().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
|
return preferences.extensionRepos().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }
|
@ -38,6 +38,8 @@ class SourcePreferences(
|
|||||||
SetMigrateSorting.Direction.ASCENDING,
|
SetMigrateSorting.Direction.ASCENDING,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun extensionRepos() = preferenceStore.getStringSet("extension_repos", emptySet())
|
||||||
|
|
||||||
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
|
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
|
||||||
|
|
||||||
fun trustedSignatures() = preferenceStore.getStringSet(Preference.appStateKey("trusted_signatures"), emptySet())
|
fun trustedSignatures() = preferenceStore.getStringSet(Preference.appStateKey("trusted_signatures"), emptySet())
|
||||||
|
@ -156,11 +156,12 @@ private fun ExtensionDetails(
|
|||||||
item {
|
item {
|
||||||
WarningBanner(SYMR.strings.redundant_extension_message)
|
WarningBanner(SYMR.strings.redundant_extension_message)
|
||||||
}
|
}
|
||||||
|
// SY <--
|
||||||
extension.isRepoSource ->
|
extension.isRepoSource ->
|
||||||
item {
|
item {
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
WarningBanner(
|
WarningBanner(
|
||||||
SYMR.strings.repo_extension_message,
|
MR.strings.repo_extension_message,
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
extension.repoUrl ?: return@clickable
|
extension.repoUrl ?: return@clickable
|
||||||
uriHandler.openUri(
|
uriHandler.openUri(
|
||||||
@ -171,7 +172,6 @@ private fun ExtensionDetails(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// SY <--
|
|
||||||
extension.isUnofficial ->
|
extension.isUnofficial ->
|
||||||
item {
|
item {
|
||||||
WarningBanner(MR.strings.unofficial_extension_message)
|
WarningBanner(MR.strings.unofficial_extension_message)
|
||||||
|
@ -340,13 +340,11 @@ private fun ExtensionItemContent(
|
|||||||
|
|
||||||
val warning = when {
|
val warning = when {
|
||||||
extension is Extension.Untrusted -> MR.strings.ext_untrusted
|
extension is Extension.Untrusted -> MR.strings.ext_untrusted
|
||||||
// SY -->
|
|
||||||
extension is Extension.Installed && extension.isRepoSource -> SYMR.strings.repo_source
|
|
||||||
extension is Extension.Available && extension.isRepoSource -> SYMR.strings.repo_source
|
|
||||||
// SY <--
|
|
||||||
extension is Extension.Installed && extension.isUnofficial -> MR.strings.ext_unofficial
|
extension is Extension.Installed && extension.isUnofficial -> MR.strings.ext_unofficial
|
||||||
extension is Extension.Installed && extension.isObsolete -> MR.strings.ext_obsolete
|
extension is Extension.Installed && extension.isObsolete -> MR.strings.ext_obsolete
|
||||||
|
// SY -->
|
||||||
extension is Extension.Installed && extension.isRedundant -> SYMR.strings.ext_redundant
|
extension is Extension.Installed && extension.isRedundant -> SYMR.strings.ext_redundant
|
||||||
|
// SY <--
|
||||||
extension.isNsfw -> MR.strings.ext_nsfw_short
|
extension.isNsfw -> MR.strings.ext_nsfw_short
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import eu.kanade.presentation.category.components.CategoryFloatingActionButton
|
import eu.kanade.presentation.category.components.CategoryFloatingActionButton
|
||||||
import eu.kanade.presentation.category.components.repo.SourceRepoContent
|
import eu.kanade.presentation.category.components.repo.SourceRepoContent
|
||||||
|
import eu.kanade.presentation.category.repos.RepoScreenState
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.tachiyomi.ui.category.repos.RepoScreenState
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.i18n.sy.SYMR
|
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
|
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
|
||||||
@ -30,7 +30,7 @@ fun SourceRepoScreen(
|
|||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
AppBar(
|
AppBar(
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
title = stringResource(SYMR.strings.action_edit_repos),
|
title = stringResource(MR.strings.label_extension_repos),
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -43,7 +43,7 @@ fun SourceRepoScreen(
|
|||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
if (state.isEmpty) {
|
if (state.isEmpty) {
|
||||||
EmptyScreen(
|
EmptyScreen(
|
||||||
SYMR.strings.information_empty_repos,
|
MR.strings.information_empty_repos,
|
||||||
modifier = Modifier.padding(paddingValues),
|
modifier = Modifier.padding(paddingValues),
|
||||||
)
|
)
|
||||||
return@Scaffold
|
return@Scaffold
|
||||||
|
@ -42,12 +42,10 @@ import kotlin.time.Duration.Companion.seconds
|
|||||||
fun CategoryCreateDialog(
|
fun CategoryCreateDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
onCreate: (String) -> Unit,
|
onCreate: (String) -> Unit,
|
||||||
// SY -->
|
|
||||||
categories: ImmutableList<String>,
|
categories: ImmutableList<String>,
|
||||||
title: String,
|
title: String,
|
||||||
extraMessage: String? = null,
|
extraMessage: String? = null,
|
||||||
alreadyExistsError: StringResource = MR.strings.error_category_exists,
|
alreadyExistsError: StringResource = MR.strings.error_category_exists,
|
||||||
// SY <--
|
|
||||||
) {
|
) {
|
||||||
var name by remember { mutableStateOf("") }
|
var name by remember { mutableStateOf("") }
|
||||||
|
|
||||||
@ -76,12 +74,9 @@ fun CategoryCreateDialog(
|
|||||||
Text(text = title)
|
Text(text = title)
|
||||||
},
|
},
|
||||||
text = {
|
text = {
|
||||||
// SY -->
|
|
||||||
Column {
|
Column {
|
||||||
if (extraMessage != null) {
|
extraMessage?.let { Text(it) }
|
||||||
Text(extraMessage)
|
|
||||||
}
|
|
||||||
// SY <--
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.focusRequester(focusRequester),
|
.focusRequester(focusRequester),
|
||||||
@ -101,9 +96,7 @@ fun CategoryCreateDialog(
|
|||||||
isError = name.isNotEmpty() && nameAlreadyExists,
|
isError = name.isNotEmpty() && nameAlreadyExists,
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
// SY -->
|
|
||||||
}
|
}
|
||||||
// SY <--
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -118,11 +111,9 @@ fun CategoryCreateDialog(
|
|||||||
fun CategoryRenameDialog(
|
fun CategoryRenameDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
onRename: (String) -> Unit,
|
onRename: (String) -> Unit,
|
||||||
// SY -->
|
|
||||||
categories: ImmutableList<String>,
|
categories: ImmutableList<String>,
|
||||||
category: String,
|
category: String,
|
||||||
alreadyExistsError: StringResource = MR.strings.error_category_exists,
|
alreadyExistsError: StringResource = MR.strings.error_category_exists,
|
||||||
// SY <--
|
|
||||||
) {
|
) {
|
||||||
var name by remember { mutableStateOf(category) }
|
var name by remember { mutableStateOf(category) }
|
||||||
var valueHasChanged by remember { mutableStateOf(false) }
|
var valueHasChanged by remember { mutableStateOf(false) }
|
||||||
@ -185,10 +176,8 @@ fun CategoryRenameDialog(
|
|||||||
fun CategoryDeleteDialog(
|
fun CategoryDeleteDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
// SY -->
|
|
||||||
title: String,
|
title: String,
|
||||||
text: String,
|
text: String,
|
||||||
// SY <--
|
|
||||||
) {
|
) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
@ -351,7 +340,3 @@ fun ChangeCategoryDialog(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Category>.anyWithName(name: String): Boolean {
|
|
||||||
return any { name == it.name }
|
|
||||||
}
|
|
||||||
|
@ -2,11 +2,23 @@ package eu.kanade.presentation.category.components.repo
|
|||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.outlined.Label
|
||||||
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
|
import androidx.compose.material3.ElevatedCard
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
@ -17,11 +29,13 @@ fun SourceRepoContent(
|
|||||||
lazyListState: LazyListState,
|
lazyListState: LazyListState,
|
||||||
paddingValues: PaddingValues,
|
paddingValues: PaddingValues,
|
||||||
onClickDelete: (String) -> Unit,
|
onClickDelete: (String) -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
contentPadding = paddingValues,
|
contentPadding = paddingValues,
|
||||||
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
|
||||||
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
items(repos) { repo ->
|
items(repos) { repo ->
|
||||||
SourceRepoListItem(
|
SourceRepoListItem(
|
||||||
@ -32,3 +46,34 @@ fun SourceRepoContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SourceRepoListItem(
|
||||||
|
repo: String,
|
||||||
|
onDelete: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
ElevatedCard(
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(
|
||||||
|
start = MaterialTheme.padding.medium,
|
||||||
|
top = MaterialTheme.padding.medium,
|
||||||
|
end = MaterialTheme.padding.medium,
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = "")
|
||||||
|
Text(text = repo, modifier = Modifier.padding(start = MaterialTheme.padding.medium))
|
||||||
|
}
|
||||||
|
Row {
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
IconButton(onClick = onDelete) {
|
||||||
|
Icon(imageVector = Icons.Outlined.Delete, contentDescription = "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
package eu.kanade.presentation.category.components.repo
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.automirrored.outlined.Label
|
|
||||||
import androidx.compose.material.icons.outlined.Delete
|
|
||||||
import androidx.compose.material.icons.outlined.Label
|
|
||||||
import androidx.compose.material3.ElevatedCard
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SourceRepoListItem(
|
|
||||||
modifier: Modifier,
|
|
||||||
repo: String,
|
|
||||||
onDelete: () -> Unit,
|
|
||||||
) {
|
|
||||||
ElevatedCard(
|
|
||||||
modifier = modifier,
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(
|
|
||||||
start = MaterialTheme.padding.medium,
|
|
||||||
top = MaterialTheme.padding.medium,
|
|
||||||
end = MaterialTheme.padding.medium,
|
|
||||||
),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = "")
|
|
||||||
Text(text = repo, modifier = Modifier.padding(start = MaterialTheme.padding.medium))
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
IconButton(onClick = onDelete) {
|
|
||||||
Icon(imageVector = Icons.Outlined.Delete, contentDescription = "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.tachiyomi.ui.category.repos
|
package eu.kanade.presentation.category.repos
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@ -14,11 +14,12 @@ import eu.kanade.presentation.category.components.CategoryDeleteDialog
|
|||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import tachiyomi.i18n.sy.SYMR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||||
|
|
||||||
class RepoScreen : Screen() {
|
class RepoScreen : Screen() {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Content() {
|
override fun Content() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
@ -48,17 +49,17 @@ class RepoScreen : Screen() {
|
|||||||
onDismissRequest = screenModel::dismissDialog,
|
onDismissRequest = screenModel::dismissDialog,
|
||||||
onCreate = { screenModel.createRepo(it) },
|
onCreate = { screenModel.createRepo(it) },
|
||||||
categories = successState.repos,
|
categories = successState.repos,
|
||||||
title = stringResource(SYMR.strings.action_add_repo),
|
title = stringResource(MR.strings.action_add_repo),
|
||||||
extraMessage = stringResource(SYMR.strings.action_add_repo_message),
|
extraMessage = stringResource(MR.strings.action_add_repo_message),
|
||||||
alreadyExistsError = SYMR.strings.error_repo_exists,
|
alreadyExistsError = MR.strings.error_repo_exists,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is RepoDialog.Delete -> {
|
is RepoDialog.Delete -> {
|
||||||
CategoryDeleteDialog(
|
CategoryDeleteDialog(
|
||||||
onDismissRequest = screenModel::dismissDialog,
|
onDismissRequest = screenModel::dismissDialog,
|
||||||
onDelete = { screenModel.deleteRepos(listOf(dialog.repo)) },
|
onDelete = { screenModel.deleteRepos(listOf(dialog.repo)) },
|
||||||
title = stringResource(SYMR.strings.delete_repo),
|
title = stringResource(MR.strings.action_delete_repo),
|
||||||
text = stringResource(SYMR.strings.delete_repo_confirmation, dialog.repo),
|
text = stringResource(MR.strings.delete_repo_confirmation, dialog.repo),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package eu.kanade.tachiyomi.ui.category.repos
|
package eu.kanade.presentation.category.repos
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
import dev.icerock.moko.resources.StringResource
|
import dev.icerock.moko.resources.StringResource
|
||||||
import eu.kanade.domain.source.interactor.CreateSourceRepo
|
import eu.kanade.domain.source.interactor.CreateSourceRepo
|
||||||
|
import eu.kanade.domain.source.interactor.DeleteSourceRepos
|
||||||
|
import eu.kanade.domain.source.interactor.GetSourceRepos
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
@ -12,10 +14,7 @@ import kotlinx.coroutines.flow.collectLatest
|
|||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.domain.source.interactor.DeleteSourceRepos
|
|
||||||
import tachiyomi.domain.source.interactor.GetSourceRepos
|
|
||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.i18n.sy.SYMR
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -87,7 +86,7 @@ class RepoScreenModel(
|
|||||||
|
|
||||||
sealed class RepoEvent {
|
sealed class RepoEvent {
|
||||||
sealed class LocalizedMessage(val stringRes: StringResource) : RepoEvent()
|
sealed class LocalizedMessage(val stringRes: StringResource) : RepoEvent()
|
||||||
data object InvalidName : LocalizedMessage(SYMR.strings.invalid_repo_name)
|
data object InvalidName : LocalizedMessage(MR.strings.invalid_repo_name)
|
||||||
data object InternalError : LocalizedMessage(MR.strings.internal_error)
|
data object InternalError : LocalizedMessage(MR.strings.internal_error)
|
||||||
}
|
}
|
||||||
|
|
@ -10,8 +10,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
|
import eu.kanade.presentation.category.repos.RepoScreen
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.tachiyomi.ui.category.repos.RepoScreen
|
|
||||||
import eu.kanade.tachiyomi.ui.category.sources.SourceCategoryScreen
|
import eu.kanade.tachiyomi.ui.category.sources.SourceCategoryScreen
|
||||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.authenticate
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
@ -34,7 +34,11 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val navigator = LocalNavigator.currentOrThrow
|
||||||
|
|
||||||
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
|
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
|
||||||
|
val reposCount by sourcePreferences.extensionRepos().collectAsState()
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
||||||
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
|
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
|
||||||
@ -45,7 +49,6 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
title = stringResource(MR.strings.label_sources),
|
title = stringResource(MR.strings.label_sources),
|
||||||
preferenceItems = persistentListOf(
|
preferenceItems = persistentListOf(
|
||||||
kotlin.run {
|
kotlin.run {
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
|
||||||
val count by sourcePreferences.sourcesTabCategories().collectAsState()
|
val count by sourcePreferences.sourcesTabCategories().collectAsState()
|
||||||
Preference.PreferenceItem.TextPreference(
|
Preference.PreferenceItem.TextPreference(
|
||||||
title = stringResource(MR.strings.action_edit_categories),
|
title = stringResource(MR.strings.action_edit_categories),
|
||||||
@ -82,22 +85,6 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceGroup(
|
|
||||||
title = stringResource(MR.strings.label_extensions),
|
|
||||||
preferenceItems = persistentListOf(
|
|
||||||
kotlin.run {
|
|
||||||
val navigator = LocalNavigator.currentOrThrow
|
|
||||||
val count by unsortedPreferences.extensionRepos().collectAsState()
|
|
||||||
Preference.PreferenceItem.TextPreference(
|
|
||||||
title = stringResource(SYMR.strings.action_edit_repos),
|
|
||||||
subtitle = pluralStringResource(SYMR.plurals.num_repos, count.size, count.size),
|
|
||||||
onClick = {
|
|
||||||
navigator.push(RepoScreen())
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// SY <--
|
// SY <--
|
||||||
Preference.PreferenceGroup(
|
Preference.PreferenceGroup(
|
||||||
title = stringResource(MR.strings.label_sources),
|
title = stringResource(MR.strings.label_sources),
|
||||||
@ -106,6 +93,13 @@ object SettingsBrowseScreen : SearchableSettings {
|
|||||||
pref = sourcePreferences.hideInLibraryItems(),
|
pref = sourcePreferences.hideInLibraryItems(),
|
||||||
title = stringResource(MR.strings.pref_hide_in_library_items),
|
title = stringResource(MR.strings.pref_hide_in_library_items),
|
||||||
),
|
),
|
||||||
|
Preference.PreferenceItem.TextPreference(
|
||||||
|
title = stringResource(MR.strings.label_extension_repos),
|
||||||
|
subtitle = pluralStringResource(MR.plurals.num_repos, reposCount.size, reposCount.size),
|
||||||
|
onClick = {
|
||||||
|
navigator.push(RepoScreen())
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceGroup(
|
Preference.PreferenceGroup(
|
||||||
|
@ -18,7 +18,6 @@ import tachiyomi.core.preference.Preference
|
|||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.UnsortedPreferences
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.time.Duration.Companion.days
|
import kotlin.time.Duration.Companion.days
|
||||||
@ -27,6 +26,7 @@ internal class ExtensionGithubApi {
|
|||||||
|
|
||||||
private val networkService: NetworkHelper by injectLazy()
|
private val networkService: NetworkHelper by injectLazy()
|
||||||
private val preferenceStore: PreferenceStore by injectLazy()
|
private val preferenceStore: PreferenceStore by injectLazy()
|
||||||
|
private val sourcePreferences: SourcePreferences by injectLazy()
|
||||||
private val extensionManager: ExtensionManager by injectLazy()
|
private val extensionManager: ExtensionManager by injectLazy()
|
||||||
private val json: Json by injectLazy()
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
@ -34,11 +34,6 @@ internal class ExtensionGithubApi {
|
|||||||
preferenceStore.getLong(Preference.appStateKey("last_ext_check"), 0)
|
preferenceStore.getLong(Preference.appStateKey("last_ext_check"), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
|
||||||
private val sourcePreferences: SourcePreferences by injectLazy()
|
|
||||||
private val unsortedPreferences: UnsortedPreferences by injectLazy()
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
private var requiresFallbackSource = false
|
private var requiresFallbackSource = false
|
||||||
|
|
||||||
suspend fun findExtensions(): List<Extension.Available> {
|
suspend fun findExtensions(): List<Extension.Available> {
|
||||||
@ -66,7 +61,7 @@ internal class ExtensionGithubApi {
|
|||||||
val extensions = with(json) {
|
val extensions = with(json) {
|
||||||
response
|
response
|
||||||
.parseAs<List<ExtensionJsonObject>>()
|
.parseAs<List<ExtensionJsonObject>>()
|
||||||
.toExtensions() /* SY --> */ + unsortedPreferences.extensionRepos()
|
.toExtensions() + sourcePreferences.extensionRepos()
|
||||||
.get()
|
.get()
|
||||||
.flatMap { repoPath ->
|
.flatMap { repoPath ->
|
||||||
val url = if (requiresFallbackSource) {
|
val url = if (requiresFallbackSource) {
|
||||||
@ -80,7 +75,6 @@ internal class ExtensionGithubApi {
|
|||||||
.parseAs<List<ExtensionJsonObject>>()
|
.parseAs<List<ExtensionJsonObject>>()
|
||||||
.toExtensions(url, repoSource = true)
|
.toExtensions(url, repoSource = true)
|
||||||
}
|
}
|
||||||
// SY <--
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check - a small number of extensions probably means something broke
|
// Sanity check - a small number of extensions probably means something broke
|
||||||
@ -138,10 +132,8 @@ internal class ExtensionGithubApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun List<ExtensionJsonObject>.toExtensions(
|
private fun List<ExtensionJsonObject>.toExtensions(
|
||||||
// SY -->
|
|
||||||
repoUrl: String = getUrlPrefix(),
|
repoUrl: String = getUrlPrefix(),
|
||||||
repoSource: Boolean = false,
|
repoSource: Boolean = false,
|
||||||
// SY <--
|
|
||||||
): List<Extension.Available> {
|
): List<Extension.Available> {
|
||||||
return this
|
return this
|
||||||
.filter {
|
.filter {
|
||||||
@ -159,17 +151,15 @@ internal class ExtensionGithubApi {
|
|||||||
isNsfw = it.nsfw == 1,
|
isNsfw = it.nsfw == 1,
|
||||||
sources = it.sources?.map(extensionSourceMapper).orEmpty(),
|
sources = it.sources?.map(extensionSourceMapper).orEmpty(),
|
||||||
apkName = it.apk,
|
apkName = it.apk,
|
||||||
iconUrl = "${/* SY --> */ repoUrl /* SY <-- */}icon/${it.pkg}.png",
|
iconUrl = "${repoUrl}icon/${it.pkg}.png",
|
||||||
// SY -->
|
|
||||||
repoUrl = repoUrl,
|
repoUrl = repoUrl,
|
||||||
isRepoSource = repoSource,
|
isRepoSource = repoSource,
|
||||||
// SY <--
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getApkUrl(extension: Extension.Available): String {
|
fun getApkUrl(extension: Extension.Available): String {
|
||||||
return /* SY --> */ "${extension.repoUrl}/apk/${extension.apkName}" // SY <--
|
return "${extension.repoUrl}/apk/${extension.apkName}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUrlPrefix(): String {
|
private fun getUrlPrefix(): String {
|
||||||
|
@ -29,10 +29,10 @@ sealed class Extension {
|
|||||||
val isObsolete: Boolean = false,
|
val isObsolete: Boolean = false,
|
||||||
val isUnofficial: Boolean = false,
|
val isUnofficial: Boolean = false,
|
||||||
val isShared: Boolean,
|
val isShared: Boolean,
|
||||||
// SY -->
|
|
||||||
val isRedundant: Boolean = false,
|
|
||||||
val repoUrl: String? = null,
|
val repoUrl: String? = null,
|
||||||
val isRepoSource: Boolean = false,
|
val isRepoSource: Boolean = false,
|
||||||
|
// SY -->
|
||||||
|
val isRedundant: Boolean = false,
|
||||||
// SY <--
|
// SY <--
|
||||||
) : Extension()
|
) : Extension()
|
||||||
|
|
||||||
@ -47,10 +47,8 @@ sealed class Extension {
|
|||||||
val sources: List<Source>,
|
val sources: List<Source>,
|
||||||
val apkName: String,
|
val apkName: String,
|
||||||
val iconUrl: String,
|
val iconUrl: String,
|
||||||
// SY -->
|
|
||||||
val repoUrl: String,
|
val repoUrl: String,
|
||||||
val isRepoSource: Boolean,
|
val isRepoSource: Boolean,
|
||||||
// SY <--
|
|
||||||
) : Extension() {
|
) : Extension() {
|
||||||
|
|
||||||
data class Source(
|
data class Source(
|
||||||
|
@ -371,7 +371,10 @@ open class BrowseSourceScreenModel(
|
|||||||
else -> {
|
else -> {
|
||||||
val preselectedIds = getCategories.await(manga.id).map { it.id }
|
val preselectedIds = getCategories.await(manga.id).map { it.id }
|
||||||
setDialog(
|
setDialog(
|
||||||
Dialog.ChangeMangaCategory(manga, categories.mapAsCheckboxState { it.id in preselectedIds }.toImmutableList()),
|
Dialog.ChangeMangaCategory(
|
||||||
|
manga,
|
||||||
|
categories.mapAsCheckboxState { it.id in preselectedIds }.toImmutableList(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,30 +56,24 @@ class CategoryScreen : Screen() {
|
|||||||
CategoryCreateDialog(
|
CategoryCreateDialog(
|
||||||
onDismissRequest = screenModel::dismissDialog,
|
onDismissRequest = screenModel::dismissDialog,
|
||||||
onCreate = screenModel::createCategory,
|
onCreate = screenModel::createCategory,
|
||||||
// SY -->
|
|
||||||
categories = successState.categories.fastMap { it.name }.toImmutableList(),
|
categories = successState.categories.fastMap { it.name }.toImmutableList(),
|
||||||
title = stringResource(MR.strings.action_add_category),
|
title = stringResource(MR.strings.action_add_category),
|
||||||
// SY <--
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is CategoryDialog.Rename -> {
|
is CategoryDialog.Rename -> {
|
||||||
CategoryRenameDialog(
|
CategoryRenameDialog(
|
||||||
onDismissRequest = screenModel::dismissDialog,
|
onDismissRequest = screenModel::dismissDialog,
|
||||||
onRename = { screenModel.renameCategory(dialog.category, it) },
|
onRename = { screenModel.renameCategory(dialog.category, it) },
|
||||||
// SY -->
|
|
||||||
categories = successState.categories.fastMap { it.name }.toImmutableList(),
|
categories = successState.categories.fastMap { it.name }.toImmutableList(),
|
||||||
category = dialog.category.name,
|
category = dialog.category.name,
|
||||||
// SY <--
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is CategoryDialog.Delete -> {
|
is CategoryDialog.Delete -> {
|
||||||
CategoryDeleteDialog(
|
CategoryDeleteDialog(
|
||||||
onDismissRequest = screenModel::dismissDialog,
|
onDismissRequest = screenModel::dismissDialog,
|
||||||
onDelete = { screenModel.deleteCategory(dialog.category.id) },
|
onDelete = { screenModel.deleteCategory(dialog.category.id) },
|
||||||
// SY -->
|
|
||||||
title = stringResource(MR.strings.delete_category),
|
title = stringResource(MR.strings.delete_category),
|
||||||
text = stringResource(MR.strings.delete_category_confirmation, dialog.category.name),
|
text = stringResource(MR.strings.delete_category_confirmation, dialog.category.name),
|
||||||
// SY <--
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is CategoryDialog.SortAlphabetically -> {
|
is CategoryDialog.SortAlphabetically -> {
|
||||||
|
@ -1117,13 +1117,15 @@ class LibraryScreenModel(
|
|||||||
val common = getCommonCategories(mangaList)
|
val common = getCommonCategories(mangaList)
|
||||||
// Get indexes of the mix categories to preselect.
|
// Get indexes of the mix categories to preselect.
|
||||||
val mix = getMixCategories(mangaList)
|
val mix = getMixCategories(mangaList)
|
||||||
val preselected = categories.map {
|
val preselected = categories
|
||||||
when (it) {
|
.map {
|
||||||
in common -> CheckboxState.State.Checked(it)
|
when (it) {
|
||||||
in mix -> CheckboxState.TriState.Exclude(it)
|
in common -> CheckboxState.State.Checked(it)
|
||||||
else -> CheckboxState.State.None(it)
|
in mix -> CheckboxState.TriState.Exclude(it)
|
||||||
|
else -> CheckboxState.State.None(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}.toImmutableList()
|
.toImmutableList()
|
||||||
mutableState.update { it.copy(dialog = Dialog.ChangeCategory(mangaList, preselected)) }
|
mutableState.update { it.copy(dialog = Dialog.ChangeCategory(mangaList, preselected)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,7 @@ class ChapterLoader(
|
|||||||
source = source,
|
source = source,
|
||||||
downloadManager = downloadManager,
|
downloadManager = downloadManager,
|
||||||
downloadProvider = downloadProvider,
|
downloadProvider = downloadProvider,
|
||||||
|
tempFileManager = tempFileManager,
|
||||||
)
|
)
|
||||||
source is HttpSource -> HttpPageLoader(chapter, source)
|
source is HttpSource -> HttpPageLoader(chapter, source)
|
||||||
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
|
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
|
||||||
@ -139,7 +140,7 @@ class ChapterLoader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider)
|
isDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager, downloadProvider, tempFileManager)
|
||||||
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
|
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
|
||||||
when (format) {
|
when (format) {
|
||||||
is Format.Directory -> DirectoryPageLoader(format.file)
|
is Format.Directory -> DirectoryPageLoader(format.file)
|
||||||
|
@ -18,10 +18,6 @@
|
|||||||
<item quantity="one">%1$d tag in sorting list. This adds a option in the library to sort by a priority based tag list, which means entries will be sorted in a way to prioritise the ones with the tags you want</item>
|
<item quantity="one">%1$d tag in sorting list. This adds a option in the library to sort by a priority based tag list, which means entries will be sorted in a way to prioritise the ones with the tags you want</item>
|
||||||
<item quantity="other">%1$d tags in sorting list. This adds a option in the library to sort by a priority based tag list, which means entries will be sorted in a way to prioritise the ones with the tags you want</item>
|
<item quantity="other">%1$d tags in sorting list. This adds a option in the library to sort by a priority based tag list, which means entries will be sorted in a way to prioritise the ones with the tags you want</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="num_repos">
|
|
||||||
<item quantity="one">%d additional repo</item>
|
|
||||||
<item quantity="other">%d additional repos</item>
|
|
||||||
</plurals>
|
|
||||||
<plurals name="migrate_entry">
|
<plurals name="migrate_entry">
|
||||||
<item quantity="one">Migrate %1$d%2$s entry?</item>
|
<item quantity="one">Migrate %1$d%2$s entry?</item>
|
||||||
<item quantity="other">Migrate %1$d%2$s entries?</item>
|
<item quantity="other">Migrate %1$d%2$s entries?</item>
|
||||||
|
@ -391,18 +391,6 @@
|
|||||||
<!-- Extension section -->
|
<!-- Extension section -->
|
||||||
<string name="ext_redundant">Redundant</string>
|
<string name="ext_redundant">Redundant</string>
|
||||||
<string name="redundant_extension_message">This extension is redundant and will not be used inside this version of Tachiyomi.</string>
|
<string name="redundant_extension_message">This extension is redundant and will not be used inside this version of Tachiyomi.</string>
|
||||||
<string name="repo_extension_message">This extension is from an external repo. Tap to view the repo.</string>
|
|
||||||
|
|
||||||
<!-- Extension Repos -->
|
|
||||||
<string name="information_empty_repos">You have no additional repos. Tap the plus button to create one for adding external extensions.</string>
|
|
||||||
<string name="action_add_repo">Add repo</string>
|
|
||||||
<string name="action_add_repo_message">Add additional repos to Tachiyomi, the format of a repo is \'username/repo\' , with username being the repo owner, and repo being the repo name</string>
|
|
||||||
<string name="action_edit_repos">Edit repos</string>
|
|
||||||
<string name="error_repo_exists">This repo already exists!</string>
|
|
||||||
<string name="invalid_repo_name">Invalid repo name</string>
|
|
||||||
<string name="repo_source">Repo source</string>
|
|
||||||
<string name="delete_repo">Delete repo</string>
|
|
||||||
<string name="delete_repo_confirmation">Do you wish to delete the repo %s?</string>
|
|
||||||
|
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="select_sources">Select sources</string>
|
<string name="select_sources">Select sources</string>
|
||||||
|
@ -18,10 +18,6 @@
|
|||||||
<item quantity="one">Ada %1$d tagar dalam daftar penyortiran. Ini menambahkan opsi di perpustakaan untuk mengurutkan berdasarkan daftar tagar berdasarkan prioritas, yang berarti manga akan diurutkan dengan cara memprioritaskan sesuai dengan tagar yang Anda inginkan</item>
|
<item quantity="one">Ada %1$d tagar dalam daftar penyortiran. Ini menambahkan opsi di perpustakaan untuk mengurutkan berdasarkan daftar tagar berdasarkan prioritas, yang berarti manga akan diurutkan dengan cara memprioritaskan sesuai dengan tagar yang Anda inginkan</item>
|
||||||
<item quantity="other">Ada %1$d tagar dalam daftar penyortiran. Ini menambahkan opsi di perpustakaan untuk mengurutkan berdasarkan daftar tagar berdasarkan prioritas, yang berarti manga akan diurutkan dengan cara memprioritaskan sesuai dengan tagar yang Anda inginkan</item>
|
<item quantity="other">Ada %1$d tagar dalam daftar penyortiran. Ini menambahkan opsi di perpustakaan untuk mengurutkan berdasarkan daftar tagar berdasarkan prioritas, yang berarti manga akan diurutkan dengan cara memprioritaskan sesuai dengan tagar yang Anda inginkan</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="num_repos">
|
|
||||||
<item quantity="one">%d repo tambahan</item>
|
|
||||||
<item quantity="other">%d repo tambahan</item>
|
|
||||||
</plurals>
|
|
||||||
<plurals name="migrate_entry">
|
<plurals name="migrate_entry">
|
||||||
<item quantity="one">Pindahkan %1$d%2$s manga?</item>
|
<item quantity="one">Pindahkan %1$d%2$s manga?</item>
|
||||||
<item quantity="other">Pindahkan %1$d%2$s manga?</item>
|
<item quantity="other">Pindahkan %1$d%2$s manga?</item>
|
||||||
|
@ -336,16 +336,6 @@
|
|||||||
<string name="ext_redundant">Duplikat</string>
|
<string name="ext_redundant">Duplikat</string>
|
||||||
<string name="redundant_extension_message">Ekstensi ini duplikat dan tak akan digunakan di dalam versi Tachiyomi ini.</string>
|
<string name="redundant_extension_message">Ekstensi ini duplikat dan tak akan digunakan di dalam versi Tachiyomi ini.</string>
|
||||||
|
|
||||||
<!-- Extension Repos -->
|
|
||||||
<string name="information_empty_repos">Kamu tidak memiliki repo tambahan. Ketuk tombol tambah untuk menambahkan ekstensi eksternal.</string>
|
|
||||||
<string name="action_add_repo">Tambah repo</string>
|
|
||||||
<string name="action_add_repo_message">Tambahkan repo tambahan ke Tachiyomi, format repo adalah \'username/repo\' , username diisi dengan pemilik repo, dan repo diisi dengan nama repo</string>
|
|
||||||
<string name="action_edit_repos">Edit repo</string>
|
|
||||||
|
|
||||||
<string name="error_repo_exists">Repo ini sudah ada!</string>
|
|
||||||
<string name="invalid_repo_name">Nama repo tidak valid</string>
|
|
||||||
<string name="repo_source">Sumber Repo</string>
|
|
||||||
|
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="select_sources">Pilih sumber</string>
|
<string name="select_sources">Pilih sumber</string>
|
||||||
<string name="select_none">Tak ada yang dipilih</string>
|
<string name="select_none">Tak ada yang dipilih</string>
|
||||||
|
@ -13,10 +13,6 @@
|
|||||||
<item quantity="one">%1$d tag na lista de ordenação. Isto dá uma opção na biblioteca de ordenar por uma lista de tags baseada em prioridade, ou seja, os mangás serão ordenados de modo a priorizar aqueles com as tags que deseja</item>
|
<item quantity="one">%1$d tag na lista de ordenação. Isto dá uma opção na biblioteca de ordenar por uma lista de tags baseada em prioridade, ou seja, os mangás serão ordenados de modo a priorizar aqueles com as tags que deseja</item>
|
||||||
<item quantity="other">%1$d tags na lista de ordenação. Isto dá uma opção na biblioteca de ordenar por uma lista de tags baseada em prioridade, ou seja, os mangás serão ordenados de modo a priorizar aqueles com as tags que deseja</item>
|
<item quantity="other">%1$d tags na lista de ordenação. Isto dá uma opção na biblioteca de ordenar por uma lista de tags baseada em prioridade, ou seja, os mangás serão ordenados de modo a priorizar aqueles com as tags que deseja</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="num_repos">
|
|
||||||
<item quantity="one">%d repositório adicional</item>
|
|
||||||
<item quantity="other">%d repositórios adicionais</item>
|
|
||||||
</plurals>
|
|
||||||
|
|
||||||
<plurals name="migrate_entry">
|
<plurals name="migrate_entry">
|
||||||
<item quantity="one">Migrar %1$d%2$s mangá?</item>
|
<item quantity="one">Migrar %1$d%2$s mangá?</item>
|
||||||
|
@ -312,15 +312,6 @@
|
|||||||
<string name="ext_redundant">Redundante</string>
|
<string name="ext_redundant">Redundante</string>
|
||||||
<string name="redundant_extension_message">Esta extensão é redundante e não será usada nesta versão do Tachiyomi.</string>
|
<string name="redundant_extension_message">Esta extensão é redundante e não será usada nesta versão do Tachiyomi.</string>
|
||||||
|
|
||||||
<!-- Extension Repos -->
|
|
||||||
<string name="information_empty_repos">Você não tem repositórios adicionais. Toque no botão Adicionar para criar um e adicionar extensões externas.</string>
|
|
||||||
<string name="action_add_repo">Adicionar repositório</string>
|
|
||||||
<string name="action_add_repo_message">Adicione repositórios adicionais ao Tachiyomi, o formato de um repositório é \'username/repo\', sendo username o dono do repositório, e repo o nome do repositório</string>
|
|
||||||
<string name="action_edit_repos">Editar repositórios</string>
|
|
||||||
<string name="error_repo_exists">Este repositório já existe!</string>
|
|
||||||
<string name="invalid_repo_name">Nome de repositório inválido</string>
|
|
||||||
<string name="repo_source">Fonte do repositório</string>
|
|
||||||
|
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="select_sources">Selecionar fontes</string>
|
<string name="select_sources">Selecionar fontes</string>
|
||||||
<string name="select_none">Selecionar nenhum</string>
|
<string name="select_none">Selecionar nenhum</string>
|
||||||
|
@ -24,12 +24,7 @@
|
|||||||
<item quantity="many">%1$d тэгов в списке сортировки. Это добавляет в библиотеку возможность сортировки по тэгам, основанному на приоритете. Это означает, что будут отображатся только те серии, которые имеют добавленные тэги.</item>
|
<item quantity="many">%1$d тэгов в списке сортировки. Это добавляет в библиотеку возможность сортировки по тэгам, основанному на приоритете. Это означает, что будут отображатся только те серии, которые имеют добавленные тэги.</item>
|
||||||
<item quantity="other">%1$d тэгов в списке сортировки. Это добавляет в библиотеку возможность сортировки по тэгам, основанному на приоритете. Это означает, что будут отображатся только те серии, которые имеют добавленные тэги.</item>
|
<item quantity="other">%1$d тэгов в списке сортировки. Это добавляет в библиотеку возможность сортировки по тэгам, основанному на приоритете. Это означает, что будут отображатся только те серии, которые имеют добавленные тэги.</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="num_repos">
|
|
||||||
<item quantity="one">%d дополнительный репозиторий</item>
|
|
||||||
<item quantity="few">%d дополнительных репозитория</item>
|
|
||||||
<item quantity="many">%d дополнительных репозиториев</item>
|
|
||||||
<item quantity="other">%d дополнительных репозиториев</item>
|
|
||||||
</plurals>
|
|
||||||
<plurals name="migrate_entry">
|
<plurals name="migrate_entry">
|
||||||
<item quantity="one">Перенести %1$d%2$s серию?</item>
|
<item quantity="one">Перенести %1$d%2$s серию?</item>
|
||||||
<item quantity="few">Перенести %1$d%2$s серии?</item>
|
<item quantity="few">Перенести %1$d%2$s серии?</item>
|
||||||
|
@ -380,18 +380,6 @@
|
|||||||
<!-- Extension section -->
|
<!-- Extension section -->
|
||||||
<string name="ext_redundant">Избыточное</string>
|
<string name="ext_redundant">Избыточное</string>
|
||||||
<string name="redundant_extension_message">Это расширение является избыточным и не будет использоваться внутри этой версии Tachiyomi.</string>
|
<string name="redundant_extension_message">Это расширение является избыточным и не будет использоваться внутри этой версии Tachiyomi.</string>
|
||||||
<string name="repo_extension_message">Это расширение из внешнего репозитория. Нажмите, чтобы просмотреть репозиторий.</string>
|
|
||||||
|
|
||||||
<!-- Extension Repos -->
|
|
||||||
<string name="information_empty_repos">У вас нет дополнительных репозиториев. Нажмите кнопку «Добавить» чтобы создать репозиторий для добавления внешних расширений.</string>
|
|
||||||
<string name="action_add_repo">Добавить репозиторий</string>
|
|
||||||
<string name="action_add_repo_message">Добавить дополнительные репозиторий в TachiyomiSY (Формат username/repo). Username - является владельцем репозитория, а repo - имя репозитория</string>
|
|
||||||
<string name="action_edit_repos">Редактировать репозитории</string>
|
|
||||||
<string name="error_repo_exists">Этот репозиторий уже существует!</string>
|
|
||||||
<string name="invalid_repo_name">Недопустимое имя репозитория</string>
|
|
||||||
<string name="repo_source">Источник репозитория</string>
|
|
||||||
<string name="delete_repo">Удалить репозиторий</string>
|
|
||||||
<string name="delete_repo_confirmation">Хотите ли вы удалить репозиторий %s?</string>
|
|
||||||
|
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="select_sources">Выберите источники</string>
|
<string name="select_sources">Выберите источники</string>
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
<plurals name="pref_tag_sorting_desc">
|
<plurals name="pref_tag_sorting_desc">
|
||||||
<item quantity="other">%1$d 个标签在排序列表中。 这在书架中增加了一个选项,以基于优先级的标签列表进行排序,这意味着作品将以你想要的标签优先的方式进行排序。</item>
|
<item quantity="other">%1$d 个标签在排序列表中。 这在书架中增加了一个选项,以基于优先级的标签列表进行排序,这意味着作品将以你想要的标签优先的方式进行排序。</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="num_repos">
|
|
||||||
<item quantity="other">%d 个额外的仓库</item>
|
|
||||||
</plurals>
|
|
||||||
|
|
||||||
<plurals name="migrate_entry">
|
<plurals name="migrate_entry">
|
||||||
<item quantity="other">迁移 %1$d%2$s 作品?</item>
|
<item quantity="other">迁移 %1$d%2$s 作品?</item>
|
||||||
|
@ -376,18 +376,6 @@
|
|||||||
<!-- Extension section -->
|
<!-- Extension section -->
|
||||||
<string name="ext_redundant">废弃</string>
|
<string name="ext_redundant">废弃</string>
|
||||||
<string name="redundant_extension_message">此插件已废弃,将不会在此版本的 Tachiyomi 上工作。</string>
|
<string name="redundant_extension_message">此插件已废弃,将不会在此版本的 Tachiyomi 上工作。</string>
|
||||||
<string name="repo_extension_message">此插件来自外部仓库。点击以浏览其仓库。</string>
|
|
||||||
|
|
||||||
<!-- Extension Repos -->
|
|
||||||
<string name="information_empty_repos">你没有额外的仓库。点击加号按钮以创建一个用于添加外部插件。</string>
|
|
||||||
<string name="action_add_repo">添加仓库</string>
|
|
||||||
<string name="action_add_repo_message">在 Tachiyomi 中添加额外的仓库,仓库的格式是 \'username/repo\',username是仓库所有者,repo是仓库名称。</string>
|
|
||||||
<string name="action_edit_repos">编辑仓库</string>
|
|
||||||
<string name="error_repo_exists">此仓库已存在!</string>
|
|
||||||
<string name="invalid_repo_name">无效的仓库名称</string>
|
|
||||||
<string name="repo_source">仓库来源</string>
|
|
||||||
<string name="delete_repo">删除仓库</string>
|
|
||||||
<string name="delete_repo_confirmation">你想要删除仓库 %s 吗?</string>
|
|
||||||
|
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="select_sources">选择来源</string>
|
<string name="select_sources">选择来源</string>
|
||||||
|
@ -12,9 +12,6 @@
|
|||||||
<plurals name="pref_tag_sorting_desc">
|
<plurals name="pref_tag_sorting_desc">
|
||||||
<item quantity="other">%1$d 個標籤在排序列表中。 這在書架中增加了一個選項,以基於優先級的標籤列表進行排序,這意味著作品將以你想要的標籤優先的方式進行排序。</item>
|
<item quantity="other">%1$d 個標籤在排序列表中。 這在書架中增加了一個選項,以基於優先級的標籤列表進行排序,這意味著作品將以你想要的標籤優先的方式進行排序。</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="num_repos">
|
|
||||||
<item quantity="other">%d 個額外的倉庫</item>
|
|
||||||
</plurals>
|
|
||||||
|
|
||||||
<plurals name="migrate_entry">
|
<plurals name="migrate_entry">
|
||||||
<item quantity="other">遷移 %1$d%2$s 作品?</item>
|
<item quantity="other">遷移 %1$d%2$s 作品?</item>
|
||||||
|
@ -376,18 +376,6 @@
|
|||||||
<!-- Extension section -->
|
<!-- Extension section -->
|
||||||
<string name="ext_redundant">廢棄</string>
|
<string name="ext_redundant">廢棄</string>
|
||||||
<string name="redundant_extension_message">此插件已廢棄,將不會在此版本的 Tachiyomi 上工作。</string>
|
<string name="redundant_extension_message">此插件已廢棄,將不會在此版本的 Tachiyomi 上工作。</string>
|
||||||
<string name="repo_extension_message">此插件來自外部倉庫。點擊以瀏覽其倉庫。</string>
|
|
||||||
|
|
||||||
<!-- Extension Repos -->
|
|
||||||
<string name="information_empty_repos">你沒有額外的倉庫。點擊加號按鈕以創建一個用於新增外部插件。</string>
|
|
||||||
<string name="action_add_repo">新增倉庫</string>
|
|
||||||
<string name="action_add_repo_message">在 Tachiyomi 中新增額外的倉庫,倉庫的格式是 \'username/repo\',username是倉庫所有者,repo是倉庫名稱。</string>
|
|
||||||
<string name="action_edit_repos">編輯倉庫</string>
|
|
||||||
<string name="error_repo_exists">此倉庫已存在!</string>
|
|
||||||
<string name="invalid_repo_name">無效的倉庫名稱</string>
|
|
||||||
<string name="repo_source">倉庫來源</string>
|
|
||||||
<string name="delete_repo">刪除倉庫</string>
|
|
||||||
<string name="delete_repo_confirmation">你想要刪除倉庫 %s 嗎?</string>
|
|
||||||
|
|
||||||
<!-- Migration -->
|
<!-- Migration -->
|
||||||
<string name="select_sources">選擇來源</string>
|
<string name="select_sources">選擇來源</string>
|
||||||
|
@ -80,4 +80,9 @@
|
|||||||
<item quantity="one">Extension update available</item>
|
<item quantity="one">Extension update available</item>
|
||||||
<item quantity="other">%d extension updates available</item>
|
<item quantity="other">%d extension updates available</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
|
|
||||||
|
<plurals name="num_repos">
|
||||||
|
<item quantity="one">%d repo</item>
|
||||||
|
<item quantity="other">%d repos</item>
|
||||||
|
</plurals>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -336,6 +336,17 @@
|
|||||||
<string name="ext_installer_shizuku_stopped">Shizuku is not running</string>
|
<string name="ext_installer_shizuku_stopped">Shizuku is not running</string>
|
||||||
<string name="ext_installer_shizuku_unavailable_dialog">Install and start Shizuku to use Shizuku as extension installer.</string>
|
<string name="ext_installer_shizuku_unavailable_dialog">Install and start Shizuku to use Shizuku as extension installer.</string>
|
||||||
|
|
||||||
|
<!-- Extension repos -->
|
||||||
|
<string name="label_extension_repos">Extension repos</string>
|
||||||
|
<string name="information_empty_repos">You have no repos set.</string>
|
||||||
|
<string name="action_add_repo">Add repo</string>
|
||||||
|
<string name="action_add_repo_message">Add additional repos to Tachiyomi, the format of a repo is \"username/repo\", with username being the repo owner, and repo being the repo name.</string>
|
||||||
|
<string name="error_repo_exists">This repo already exists!</string>
|
||||||
|
<string name="action_delete_repo">Delete repo</string>
|
||||||
|
<string name="invalid_repo_name">Invalid repo name</string>
|
||||||
|
<string name="delete_repo_confirmation">Do you wish to delete the repo \"%s\"?</string>
|
||||||
|
<string name="repo_extension_message">This extension is from an external repo. Tap to view the repo.</string>
|
||||||
|
|
||||||
<!-- Reader section -->
|
<!-- Reader section -->
|
||||||
<string name="pref_fullscreen">Fullscreen</string>
|
<string name="pref_fullscreen">Fullscreen</string>
|
||||||
<string name="pref_show_navigation_mode">Show tap zones overlay</string>
|
<string name="pref_show_navigation_mode">Show tap zones overlay</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user