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:
arkon 2024-01-05 17:28:08 -05:00 committed by Jobobby04
parent b677f81fb1
commit 24a56a5529
35 changed files with 133 additions and 244 deletions

View File

@ -11,8 +11,11 @@ import eu.kanade.domain.manga.interactor.GetExcludedScanlators
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.CreateSourceRepo
import eu.kanade.domain.source.interactor.DeleteSourceRepos
import eu.kanade.domain.source.interactor.GetEnabledSources
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.SetMigrateSorting
import eu.kanade.domain.source.interactor.ToggleLanguage
@ -167,5 +170,9 @@ class DomainModule : InjektModule {
addFactory { ToggleLanguage(get()) }
addFactory { ToggleSource(get()) }
addFactory { ToggleSourcePin(get()) }
addFactory { CreateSourceRepo(get()) }
addFactory { DeleteSourceRepos(get()) }
addFactory { GetSourceRepos(get()) }
}
}

View File

@ -7,7 +7,6 @@ import eu.kanade.domain.manga.interactor.GetPagePreviews
import eu.kanade.domain.manga.interactor.GetSortTag
import eu.kanade.domain.manga.interactor.ReorderSortTag
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.GetExhSavedSearch
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.DeleteFeedSavedSearchById
import tachiyomi.domain.source.interactor.DeleteSavedSearchById
import tachiyomi.domain.source.interactor.DeleteSourceRepos
import tachiyomi.domain.source.interactor.GetFeedSavedSearchBySourceId
import tachiyomi.domain.source.interactor.GetFeedSavedSearchGlobal
import tachiyomi.domain.source.interactor.GetSavedSearchById
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceId
import tachiyomi.domain.source.interactor.GetSavedSearchBySourceIdFeed
import tachiyomi.domain.source.interactor.GetSavedSearchGlobalFeed
import tachiyomi.domain.source.interactor.GetSourceRepos
import tachiyomi.domain.source.interactor.InsertFeedSavedSearch
import tachiyomi.domain.source.interactor.InsertSavedSearch
import tachiyomi.domain.source.repository.FeedSavedSearchRepository
@ -94,9 +91,6 @@ class SYDomainModule : InjektModule {
addFactory { FilterSerializer() }
addFactory { GetHistoryByMangaId(get()) }
addFactory { GetChapterByUrl(get()) }
addFactory { CreateSourceRepo(get()) }
addFactory { DeleteSourceRepos(get()) }
addFactory { GetSourceRepos(get()) }
addFactory { GetSourceCategories(get()) }
addFactory { CreateSourceCategory(get()) }
addFactory { RenameSourceCategory(get(), get()) }

View File

@ -1,9 +1,9 @@
package eu.kanade.domain.source.interactor
import eu.kanade.domain.source.service.SourcePreferences
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 {
// Do not allow invalid formats

View File

@ -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>) {
preferences.extensionRepos().set(

View File

@ -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.map
import tachiyomi.domain.UnsortedPreferences
class GetSourceRepos(private val preferences: UnsortedPreferences) {
class GetSourceRepos(private val preferences: SourcePreferences) {
fun subscribe(): Flow<List<String>> {
return preferences.extensionRepos().changes().map { it.sortedWith(String.CASE_INSENSITIVE_ORDER) }

View File

@ -38,6 +38,8 @@ class SourcePreferences(
SetMigrateSorting.Direction.ASCENDING,
)
fun extensionRepos() = preferenceStore.getStringSet("extension_repos", emptySet())
fun extensionUpdatesCount() = preferenceStore.getInt("ext_updates_count", 0)
fun trustedSignatures() = preferenceStore.getStringSet(Preference.appStateKey("trusted_signatures"), emptySet())

View File

@ -156,11 +156,12 @@ private fun ExtensionDetails(
item {
WarningBanner(SYMR.strings.redundant_extension_message)
}
// SY <--
extension.isRepoSource ->
item {
val uriHandler = LocalUriHandler.current
WarningBanner(
SYMR.strings.repo_extension_message,
MR.strings.repo_extension_message,
modifier = Modifier.clickable {
extension.repoUrl ?: return@clickable
uriHandler.openUri(
@ -171,7 +172,6 @@ private fun ExtensionDetails(
},
)
}
// SY <--
extension.isUnofficial ->
item {
WarningBanner(MR.strings.unofficial_extension_message)

View File

@ -340,13 +340,11 @@ private fun ExtensionItemContent(
val warning = when {
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.isObsolete -> MR.strings.ext_obsolete
// SY -->
extension is Extension.Installed && extension.isRedundant -> SYMR.strings.ext_redundant
// SY <--
extension.isNsfw -> MR.strings.ext_nsfw_short
else -> null
}

View File

@ -8,9 +8,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import eu.kanade.presentation.category.components.CategoryFloatingActionButton
import eu.kanade.presentation.category.components.repo.SourceRepoContent
import eu.kanade.presentation.category.repos.RepoScreenState
import eu.kanade.presentation.components.AppBar
import eu.kanade.tachiyomi.ui.category.repos.RepoScreenState
import tachiyomi.i18n.sy.SYMR
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
@ -30,7 +30,7 @@ fun SourceRepoScreen(
topBar = { scrollBehavior ->
AppBar(
navigateUp = navigateUp,
title = stringResource(SYMR.strings.action_edit_repos),
title = stringResource(MR.strings.label_extension_repos),
scrollBehavior = scrollBehavior,
)
},
@ -43,7 +43,7 @@ fun SourceRepoScreen(
) { paddingValues ->
if (state.isEmpty) {
EmptyScreen(
SYMR.strings.information_empty_repos,
MR.strings.information_empty_repos,
modifier = Modifier.padding(paddingValues),
)
return@Scaffold

View File

@ -42,12 +42,10 @@ import kotlin.time.Duration.Companion.seconds
fun CategoryCreateDialog(
onDismissRequest: () -> Unit,
onCreate: (String) -> Unit,
// SY -->
categories: ImmutableList<String>,
title: String,
extraMessage: String? = null,
alreadyExistsError: StringResource = MR.strings.error_category_exists,
// SY <--
) {
var name by remember { mutableStateOf("") }
@ -76,12 +74,9 @@ fun CategoryCreateDialog(
Text(text = title)
},
text = {
// SY -->
Column {
if (extraMessage != null) {
Text(extraMessage)
}
// SY <--
extraMessage?.let { Text(it) }
OutlinedTextField(
modifier = Modifier
.focusRequester(focusRequester),
@ -101,9 +96,7 @@ fun CategoryCreateDialog(
isError = name.isNotEmpty() && nameAlreadyExists,
singleLine = true,
)
// SY -->
}
// SY <--
},
)
@ -118,11 +111,9 @@ fun CategoryCreateDialog(
fun CategoryRenameDialog(
onDismissRequest: () -> Unit,
onRename: (String) -> Unit,
// SY -->
categories: ImmutableList<String>,
category: String,
alreadyExistsError: StringResource = MR.strings.error_category_exists,
// SY <--
) {
var name by remember { mutableStateOf(category) }
var valueHasChanged by remember { mutableStateOf(false) }
@ -185,10 +176,8 @@ fun CategoryRenameDialog(
fun CategoryDeleteDialog(
onDismissRequest: () -> Unit,
onDelete: () -> Unit,
// SY -->
title: String,
text: String,
// SY <--
) {
AlertDialog(
onDismissRequest = onDismissRequest,
@ -351,7 +340,3 @@ fun ChangeCategoryDialog(
},
)
}
private fun List<Category>.anyWithName(name: String): Boolean {
return any { name == it.name }
}

View File

@ -2,11 +2,23 @@ package eu.kanade.presentation.category.components.repo
import androidx.compose.foundation.layout.Arrangement
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.LazyListState
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.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import kotlinx.collections.immutable.ImmutableList
import tachiyomi.presentation.core.components.material.padding
@ -17,11 +29,13 @@ fun SourceRepoContent(
lazyListState: LazyListState,
paddingValues: PaddingValues,
onClickDelete: (String) -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(
state = lazyListState,
contentPadding = paddingValues,
verticalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
modifier = modifier,
) {
items(repos) { repo ->
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 = "")
}
}
}
}

View File

@ -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 = "")
}
}
}
}

View File

@ -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.LaunchedEffect
@ -14,11 +14,12 @@ import eu.kanade.presentation.category.components.CategoryDeleteDialog
import eu.kanade.presentation.util.Screen
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.collectLatest
import tachiyomi.i18n.sy.SYMR
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.screens.LoadingScreen
class RepoScreen : Screen() {
@Composable
override fun Content() {
val context = LocalContext.current
@ -48,17 +49,17 @@ class RepoScreen : Screen() {
onDismissRequest = screenModel::dismissDialog,
onCreate = { screenModel.createRepo(it) },
categories = successState.repos,
title = stringResource(SYMR.strings.action_add_repo),
extraMessage = stringResource(SYMR.strings.action_add_repo_message),
alreadyExistsError = SYMR.strings.error_repo_exists,
title = stringResource(MR.strings.action_add_repo),
extraMessage = stringResource(MR.strings.action_add_repo_message),
alreadyExistsError = MR.strings.error_repo_exists,
)
}
is RepoDialog.Delete -> {
CategoryDeleteDialog(
onDismissRequest = screenModel::dismissDialog,
onDelete = { screenModel.deleteRepos(listOf(dialog.repo)) },
title = stringResource(SYMR.strings.delete_repo),
text = stringResource(SYMR.strings.delete_repo_confirmation, dialog.repo),
title = stringResource(MR.strings.action_delete_repo),
text = stringResource(MR.strings.delete_repo_confirmation, dialog.repo),
)
}
}

View File

@ -1,10 +1,12 @@
package eu.kanade.tachiyomi.ui.category.repos
package eu.kanade.presentation.category.repos
import androidx.compose.runtime.Immutable
import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import dev.icerock.moko.resources.StringResource
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.toImmutableList
import kotlinx.coroutines.channels.Channel
@ -12,10 +14,7 @@ import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
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.sy.SYMR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -87,7 +86,7 @@ class RepoScreenModel(
sealed class 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)
}

View File

@ -10,8 +10,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.category.repos.RepoScreen
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.util.system.AuthenticatorUtil.authenticate
import kotlinx.collections.immutable.persistentListOf
@ -34,7 +34,11 @@ object SettingsBrowseScreen : SearchableSettings {
@Composable
override fun getPreferences(): List<Preference> {
val context = LocalContext.current
val navigator = LocalNavigator.currentOrThrow
val sourcePreferences = remember { Injekt.get<SourcePreferences>() }
val reposCount by sourcePreferences.extensionRepos().collectAsState()
// SY -->
val uiPreferences = remember { Injekt.get<UiPreferences>() }
val unsortedPreferences = remember { Injekt.get<UnsortedPreferences>() }
@ -45,7 +49,6 @@ object SettingsBrowseScreen : SearchableSettings {
title = stringResource(MR.strings.label_sources),
preferenceItems = persistentListOf(
kotlin.run {
val navigator = LocalNavigator.currentOrThrow
val count by sourcePreferences.sourcesTabCategories().collectAsState()
Preference.PreferenceItem.TextPreference(
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 <--
Preference.PreferenceGroup(
title = stringResource(MR.strings.label_sources),
@ -106,6 +93,13 @@ object SettingsBrowseScreen : SearchableSettings {
pref = sourcePreferences.hideInLibraryItems(),
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(

View File

@ -18,7 +18,6 @@ import tachiyomi.core.preference.Preference
import tachiyomi.core.preference.PreferenceStore
import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.system.logcat
import tachiyomi.domain.UnsortedPreferences
import uy.kohesive.injekt.injectLazy
import java.time.Instant
import kotlin.time.Duration.Companion.days
@ -27,6 +26,7 @@ internal class ExtensionGithubApi {
private val networkService: NetworkHelper by injectLazy()
private val preferenceStore: PreferenceStore by injectLazy()
private val sourcePreferences: SourcePreferences by injectLazy()
private val extensionManager: ExtensionManager by injectLazy()
private val json: Json by injectLazy()
@ -34,11 +34,6 @@ internal class ExtensionGithubApi {
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
suspend fun findExtensions(): List<Extension.Available> {
@ -66,7 +61,7 @@ internal class ExtensionGithubApi {
val extensions = with(json) {
response
.parseAs<List<ExtensionJsonObject>>()
.toExtensions() /* SY --> */ + unsortedPreferences.extensionRepos()
.toExtensions() + sourcePreferences.extensionRepos()
.get()
.flatMap { repoPath ->
val url = if (requiresFallbackSource) {
@ -80,7 +75,6 @@ internal class ExtensionGithubApi {
.parseAs<List<ExtensionJsonObject>>()
.toExtensions(url, repoSource = true)
}
// SY <--
}
// Sanity check - a small number of extensions probably means something broke
@ -138,10 +132,8 @@ internal class ExtensionGithubApi {
}
private fun List<ExtensionJsonObject>.toExtensions(
// SY -->
repoUrl: String = getUrlPrefix(),
repoSource: Boolean = false,
// SY <--
): List<Extension.Available> {
return this
.filter {
@ -159,17 +151,15 @@ internal class ExtensionGithubApi {
isNsfw = it.nsfw == 1,
sources = it.sources?.map(extensionSourceMapper).orEmpty(),
apkName = it.apk,
iconUrl = "${/* SY --> */ repoUrl /* SY <-- */}icon/${it.pkg}.png",
// SY -->
iconUrl = "${repoUrl}icon/${it.pkg}.png",
repoUrl = repoUrl,
isRepoSource = repoSource,
// SY <--
)
}
}
fun getApkUrl(extension: Extension.Available): String {
return /* SY --> */ "${extension.repoUrl}/apk/${extension.apkName}" // SY <--
return "${extension.repoUrl}/apk/${extension.apkName}"
}
private fun getUrlPrefix(): String {

View File

@ -29,10 +29,10 @@ sealed class Extension {
val isObsolete: Boolean = false,
val isUnofficial: Boolean = false,
val isShared: Boolean,
// SY -->
val isRedundant: Boolean = false,
val repoUrl: String? = null,
val isRepoSource: Boolean = false,
// SY -->
val isRedundant: Boolean = false,
// SY <--
) : Extension()
@ -47,10 +47,8 @@ sealed class Extension {
val sources: List<Source>,
val apkName: String,
val iconUrl: String,
// SY -->
val repoUrl: String,
val isRepoSource: Boolean,
// SY <--
) : Extension() {
data class Source(

View File

@ -371,7 +371,10 @@ open class BrowseSourceScreenModel(
else -> {
val preselectedIds = getCategories.await(manga.id).map { it.id }
setDialog(
Dialog.ChangeMangaCategory(manga, categories.mapAsCheckboxState { it.id in preselectedIds }.toImmutableList()),
Dialog.ChangeMangaCategory(
manga,
categories.mapAsCheckboxState { it.id in preselectedIds }.toImmutableList(),
),
)
}
}

View File

@ -56,30 +56,24 @@ class CategoryScreen : Screen() {
CategoryCreateDialog(
onDismissRequest = screenModel::dismissDialog,
onCreate = screenModel::createCategory,
// SY -->
categories = successState.categories.fastMap { it.name }.toImmutableList(),
title = stringResource(MR.strings.action_add_category),
// SY <--
)
}
is CategoryDialog.Rename -> {
CategoryRenameDialog(
onDismissRequest = screenModel::dismissDialog,
onRename = { screenModel.renameCategory(dialog.category, it) },
// SY -->
categories = successState.categories.fastMap { it.name }.toImmutableList(),
category = dialog.category.name,
// SY <--
)
}
is CategoryDialog.Delete -> {
CategoryDeleteDialog(
onDismissRequest = screenModel::dismissDialog,
onDelete = { screenModel.deleteCategory(dialog.category.id) },
// SY -->
title = stringResource(MR.strings.delete_category),
text = stringResource(MR.strings.delete_category_confirmation, dialog.category.name),
// SY <--
)
}
is CategoryDialog.SortAlphabetically -> {

View File

@ -1117,13 +1117,15 @@ class LibraryScreenModel(
val common = getCommonCategories(mangaList)
// Get indexes of the mix categories to preselect.
val mix = getMixCategories(mangaList)
val preselected = categories.map {
val preselected = categories
.map {
when (it) {
in common -> CheckboxState.State.Checked(it)
in mix -> CheckboxState.TriState.Exclude(it)
else -> CheckboxState.State.None(it)
}
}.toImmutableList()
}
.toImmutableList()
mutableState.update { it.copy(dialog = Dialog.ChangeCategory(mangaList, preselected)) }
}
}

View File

@ -121,6 +121,7 @@ class ChapterLoader(
source = source,
downloadManager = downloadManager,
downloadProvider = downloadProvider,
tempFileManager = tempFileManager,
)
source is HttpSource -> HttpPageLoader(chapter, source)
source is LocalSource -> source.getFormat(chapter.chapter).let { format ->
@ -139,7 +140,7 @@ class ChapterLoader(
}
}
// 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 ->
when (format) {
is Format.Directory -> DirectoryPageLoader(format.file)

View 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="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 name="num_repos">
<item quantity="one">%d additional repo</item>
<item quantity="other">%d additional repos</item>
</plurals>
<plurals name="migrate_entry">
<item quantity="one">Migrate %1$d%2$s entry?</item>
<item quantity="other">Migrate %1$d%2$s entries?</item>

View File

@ -391,18 +391,6 @@
<!-- Extension section -->
<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="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 -->
<string name="select_sources">Select sources</string>

View File

@ -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="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 name="num_repos">
<item quantity="one">%d repo tambahan</item>
<item quantity="other">%d repo tambahan</item>
</plurals>
<plurals name="migrate_entry">
<item quantity="one">Pindahkan %1$d%2$s manga?</item>
<item quantity="other">Pindahkan %1$d%2$s manga?</item>

View File

@ -336,16 +336,6 @@
<string name="ext_redundant">Duplikat</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 -->
<string name="select_sources">Pilih sumber</string>
<string name="select_none">Tak ada yang dipilih</string>

View File

@ -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="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 name="num_repos">
<item quantity="one">%d repositório adicional</item>
<item quantity="other">%d repositórios adicionais</item>
</plurals>
<plurals name="migrate_entry">
<item quantity="one">Migrar %1$d%2$s mangá?</item>

View File

@ -312,15 +312,6 @@
<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>
<!-- 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 -->
<string name="select_sources">Selecionar fontes</string>
<string name="select_none">Selecionar nenhum</string>

View File

@ -24,12 +24,7 @@
<item quantity="many">%1$d тэгов в списке сортировки. Это добавляет в библиотеку возможность сортировки по тэгам, основанному на приоритете. Это означает, что будут отображатся только те серии, которые имеют добавленные тэги.</item>
<item quantity="other">%1$d тэгов в списке сортировки. Это добавляет в библиотеку возможность сортировки по тэгам, основанному на приоритете. Это означает, что будут отображатся только те серии, которые имеют добавленные тэги.</item>
</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">
<item quantity="one">Перенести %1$d%2$s серию?</item>
<item quantity="few">Перенести %1$d%2$s серии?</item>

View File

@ -380,18 +380,6 @@
<!-- Extension section -->
<string name="ext_redundant">Избыточное</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 -->
<string name="select_sources">Выберите источники</string>

View File

@ -12,9 +12,6 @@
<plurals name="pref_tag_sorting_desc">
<item quantity="other">%1$d 个标签在排序列表中。 这在书架中增加了一个选项,以基于优先级的标签列表进行排序,这意味着作品将以你想要的标签优先的方式进行排序。</item>
</plurals>
<plurals name="num_repos">
<item quantity="other">%d 个额外的仓库</item>
</plurals>
<plurals name="migrate_entry">
<item quantity="other">迁移 %1$d%2$s 作品?</item>

View File

@ -376,18 +376,6 @@
<!-- Extension section -->
<string name="ext_redundant">废弃</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 -->
<string name="select_sources">选择来源</string>

View File

@ -12,9 +12,6 @@
<plurals name="pref_tag_sorting_desc">
<item quantity="other">%1$d 個標籤在排序列表中。 這在書架中增加了一個選項,以基於優先級的標籤列表進行排序,這意味著作品將以你想要的標籤優先的方式進行排序。</item>
</plurals>
<plurals name="num_repos">
<item quantity="other">%d 個額外的倉庫</item>
</plurals>
<plurals name="migrate_entry">
<item quantity="other">遷移 %1$d%2$s 作品?</item>

View File

@ -376,18 +376,6 @@
<!-- Extension section -->
<string name="ext_redundant">廢棄</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 -->
<string name="select_sources">選擇來源</string>

View File

@ -80,4 +80,9 @@
<item quantity="one">Extension update available</item>
<item quantity="other">%d extension updates available</item>
</plurals>
<plurals name="num_repos">
<item quantity="one">%d repo</item>
<item quantity="other">%d repos</item>
</plurals>
</resources>

View File

@ -336,6 +336,17 @@
<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>
<!-- 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 -->
<string name="pref_fullscreen">Fullscreen</string>
<string name="pref_show_navigation_mode">Show tap zones overlay</string>