mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-21 12:17:12 +03:00
parent
375a252a69
commit
91de0ed82e
189 changed files with 1500 additions and 1349 deletions
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
|
@ -12,7 +12,7 @@ jobs:
|
|||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v4
|
||||
- uses: dessant/lock-threads@v5
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '2'
|
||||
|
|
|
@ -174,6 +174,7 @@ dependencies {
|
|||
implementation(compose.accompanist.permissions)
|
||||
implementation(compose.accompanist.themeadapter)
|
||||
implementation(compose.accompanist.systemuicontroller)
|
||||
lintChecks(compose.lintchecks)
|
||||
|
||||
implementation(androidx.paging.runtime)
|
||||
implementation(androidx.paging.compose)
|
||||
|
@ -181,6 +182,7 @@ dependencies {
|
|||
implementation(libs.bundles.sqlite)
|
||||
|
||||
implementation(kotlinx.reflect)
|
||||
implementation(kotlinx.immutables)
|
||||
|
||||
implementation(platform(kotlinx.coroutines.bom))
|
||||
implementation(kotlinx.bundles.coroutines)
|
||||
|
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowForward
|
||||
import androidx.compose.material.icons.outlined.ArrowForward
|
||||
import androidx.compose.material.icons.outlined.Error
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
|
@ -54,7 +55,7 @@ fun GlobalSearchResultItem(
|
|||
Text(text = subtitle)
|
||||
}
|
||||
IconButton(onClick = onClick) {
|
||||
Icon(imageVector = Icons.Outlined.ArrowForward, contentDescription = null)
|
||||
Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null)
|
||||
}
|
||||
}
|
||||
content()
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.History
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
|
@ -54,6 +55,7 @@ import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
|||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||
import eu.kanade.tachiyomi.ui.browse.anime.extension.details.AnimeExtensionDetailsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
@ -79,40 +81,42 @@ fun AnimeExtensionDetailsScreen(
|
|||
navigateUp = navigateUp,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
actions = buildList {
|
||||
if (state.extension?.isUnofficial == false) {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.whats_new),
|
||||
icon = Icons.Outlined.History,
|
||||
onClick = onClickWhatsNew,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_faq_and_guides),
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
onClick = onClickReadme,
|
||||
actions = persistentListOf<AppBar.AppBarAction>().builder()
|
||||
.apply {
|
||||
if (state.extension?.isUnofficial == false) {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.whats_new),
|
||||
icon = Icons.Outlined.History,
|
||||
onClick = onClickWhatsNew,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_faq_and_guides),
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = onClickReadme,
|
||||
),
|
||||
)
|
||||
}
|
||||
addAll(
|
||||
listOf(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_enable_all),
|
||||
onClick = onClickEnableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_disable_all),
|
||||
onClick = onClickDisableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.pref_clear_cookies),
|
||||
onClick = onClickClearCookies,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
addAll(
|
||||
listOf(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_enable_all),
|
||||
onClick = onClickEnableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_disable_all),
|
||||
onClick = onClickDisableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.pref_clear_cookies),
|
||||
onClick = onClickClearCookies,
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
.build(),
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
|
@ -186,7 +190,6 @@ private fun AnimeExtensionDetails(
|
|||
key = { it.source.id },
|
||||
) { source ->
|
||||
SourceSwitchPreference(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
source = source,
|
||||
onClickSourcePreferences = onClickSourcePreferences,
|
||||
onClickSource = onClickSource,
|
||||
|
@ -321,10 +324,10 @@ private fun DetailsHeader(
|
|||
|
||||
@Composable
|
||||
private fun InfoText(
|
||||
modifier: Modifier,
|
||||
primaryText: String,
|
||||
primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge,
|
||||
secondaryText: String,
|
||||
modifier: Modifier = Modifier,
|
||||
primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge,
|
||||
onClick: (() -> Unit)? = null,
|
||||
) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
|
@ -364,10 +367,10 @@ private fun InfoDivider() {
|
|||
|
||||
@Composable
|
||||
private fun SourceSwitchPreference(
|
||||
modifier: Modifier = Modifier,
|
||||
source: AnimeExtensionSourceItem,
|
||||
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
||||
onClickSource: (sourceId: Long) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ private fun AnimeExtensionFilterContent(
|
|||
) {
|
||||
items(state.languages) { language ->
|
||||
SwitchPreferenceWidget(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
title = LocaleHelper.getSourceDisplayName(language, context),
|
||||
checked = language in state.enabledLanguages,
|
||||
onCheckedChanged = { onClickLang(language) },
|
||||
|
|
|
@ -147,14 +147,13 @@ private fun AnimeExtensionContent(
|
|||
}
|
||||
ExtensionHeader(
|
||||
textRes = header.textRes,
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
action = action,
|
||||
)
|
||||
}
|
||||
is AnimeExtensionUiModel.Header.Text -> {
|
||||
ExtensionHeader(
|
||||
text = header.text,
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +165,7 @@ private fun AnimeExtensionContent(
|
|||
key = { "extension-${it.hashCode()}" },
|
||||
) { item ->
|
||||
AnimeExtensionItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
item = item,
|
||||
onClickItem = {
|
||||
when (it) {
|
||||
|
@ -216,12 +215,12 @@ private fun AnimeExtensionContent(
|
|||
|
||||
@Composable
|
||||
private fun AnimeExtensionItem(
|
||||
modifier: Modifier = Modifier,
|
||||
item: AnimeExtensionUiModel.Item,
|
||||
onClickItem: (AnimeExtension) -> Unit,
|
||||
onLongClickItem: (AnimeExtension) -> Unit,
|
||||
onClickItemCancel: (AnimeExtension) -> Unit,
|
||||
onClickItemAction: (AnimeExtension) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val (extension, installStep) = item
|
||||
BaseBrowseItem(
|
||||
|
|
|
@ -68,7 +68,7 @@ private fun AnimeSourcesFilterContent(
|
|||
contentType = "source-filter-header",
|
||||
) {
|
||||
AnimeSourcesFilterHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
language = language,
|
||||
enabled = enabled,
|
||||
onClickItem = onClickLanguage,
|
||||
|
@ -81,7 +81,7 @@ private fun AnimeSourcesFilterContent(
|
|||
contentType = { "source-filter-item" },
|
||||
) { source ->
|
||||
AnimeSourcesFilterItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = source,
|
||||
isEnabled = "${source.id}" !in state.disabledSources,
|
||||
onClickItem = onClickSource,
|
||||
|
@ -94,10 +94,10 @@ private fun AnimeSourcesFilterContent(
|
|||
|
||||
@Composable
|
||||
fun AnimeSourcesFilterHeader(
|
||||
modifier: Modifier,
|
||||
language: String,
|
||||
enabled: Boolean,
|
||||
onClickItem: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SwitchPreferenceWidget(
|
||||
modifier = modifier,
|
||||
|
@ -109,10 +109,10 @@ fun AnimeSourcesFilterHeader(
|
|||
|
||||
@Composable
|
||||
private fun AnimeSourcesFilterItem(
|
||||
modifier: Modifier,
|
||||
source: AnimeSource,
|
||||
isEnabled: Boolean,
|
||||
onClickItem: (AnimeSource) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseAnimeSourceItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -74,12 +74,12 @@ fun AnimeSourcesScreen(
|
|||
when (model) {
|
||||
is AnimeSourceUiModel.Header -> {
|
||||
AnimeSourceHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
language = model.language,
|
||||
)
|
||||
}
|
||||
is AnimeSourceUiModel.Item -> AnimeSourceItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = model.source,
|
||||
onClickItem = onClickItem,
|
||||
onLongClickItem = onLongClickItem,
|
||||
|
@ -94,8 +94,8 @@ fun AnimeSourcesScreen(
|
|||
|
||||
@Composable
|
||||
private fun AnimeSourceHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
language: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
|
@ -111,11 +111,11 @@ private fun AnimeSourceHeader(
|
|||
|
||||
@Composable
|
||||
private fun AnimeSourceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
source: AnimeSource,
|
||||
onClickItem: (AnimeSource, Listing) -> Unit,
|
||||
onLongClickItem: (AnimeSource) -> Unit,
|
||||
onClickPin: (AnimeSource) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseAnimeSourceItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.Public
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
|
@ -24,6 +25,7 @@ import eu.kanade.presentation.components.AppBar
|
|||
import eu.kanade.presentation.util.formattedMessage
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.AnimeSource
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||
|
@ -76,15 +78,15 @@ fun BrowseAnimeSourceContent(
|
|||
modifier = Modifier.padding(contentPadding),
|
||||
message = getErrorMessage(errorState),
|
||||
actions = if (source is LocalAnimeSource) {
|
||||
listOf(
|
||||
persistentListOf(
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.local_source_help_guide,
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = onLocalAnimeSourceHelpClick,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
listOf(
|
||||
persistentListOf(
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.action_retry,
|
||||
icon = Icons.Outlined.Refresh,
|
||||
|
@ -97,7 +99,7 @@ fun BrowseAnimeSourceContent(
|
|||
),
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.label_help,
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = onHelpClick,
|
||||
),
|
||||
)
|
||||
|
@ -145,7 +147,7 @@ fun BrowseAnimeSourceContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MissingSourceScreen(
|
||||
internal fun MissingSourceScreen(
|
||||
source: StubAnimeSource,
|
||||
navigateUp: () -> Unit,
|
||||
) {
|
||||
|
|
|
@ -60,13 +60,13 @@ fun GlobalAnimeSearchScreen(
|
|||
|
||||
@Composable
|
||||
internal fun GlobalSearchContent(
|
||||
fromSourceId: Long? = null,
|
||||
items: Map<AnimeCatalogueSource, AnimeSearchItemResult>,
|
||||
contentPadding: PaddingValues,
|
||||
getAnime: @Composable (Anime) -> State<Anime>,
|
||||
onClickSource: (AnimeCatalogueSource) -> Unit,
|
||||
onClickItem: (Anime) -> Unit,
|
||||
onLongClickItem: (Anime) -> Unit,
|
||||
fromSourceId: Long? = null,
|
||||
) {
|
||||
LazyColumn(
|
||||
contentPadding = contentPadding,
|
||||
|
|
|
@ -70,10 +70,10 @@ private fun MigrateAnimeContent(
|
|||
|
||||
@Composable
|
||||
private fun MigrateAnimeItem(
|
||||
modifier: Modifier = Modifier,
|
||||
anime: Anime,
|
||||
onClickItem: (Anime) -> Unit,
|
||||
onClickCover: (Anime) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseAnimeListItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -132,7 +132,7 @@ private fun MigrateAnimeSourceList(
|
|||
key = { (source, _) -> "migrate-${source.id}" },
|
||||
) { (source, count) ->
|
||||
MigrateAnimeSourceItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = source,
|
||||
count = count,
|
||||
onClickItem = { onClickItem(source) },
|
||||
|
@ -144,11 +144,11 @@ private fun MigrateAnimeSourceList(
|
|||
|
||||
@Composable
|
||||
private fun MigrateAnimeSourceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
source: AnimeSource,
|
||||
count: Long,
|
||||
onClickItem: () -> Unit,
|
||||
onLongClickItem: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseAnimeSourceItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -17,8 +17,8 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun BaseAnimeSourceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
source: AnimeSource,
|
||||
modifier: Modifier = Modifier,
|
||||
showLanguageInContent: Boolean = true,
|
||||
onClickItem: () -> Unit = {},
|
||||
onLongClickItem: () -> Unit = {},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.presentation.browse.anime.components
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ViewList
|
||||
import androidx.compose.material.icons.filled.ViewList
|
||||
import androidx.compose.material.icons.filled.ViewModule
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -20,6 +21,7 @@ import eu.kanade.presentation.components.SearchToolbar
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.animesource.AnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||
import tachiyomi.source.local.entries.anime.LocalAnimeSource
|
||||
|
||||
|
@ -53,32 +55,44 @@ fun BrowseAnimeSourceToolbar(
|
|||
onClickCloseSearch = navigateUp,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
actions = listOfNotNull(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_display_mode),
|
||||
icon = if (displayMode == LibraryDisplayMode.List) {
|
||||
Icons.Filled.ViewList
|
||||
actions = persistentListOf<AppBar.AppBarAction>().builder()
|
||||
.apply {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_display_mode),
|
||||
icon = if (displayMode == LibraryDisplayMode.List) {
|
||||
Icons.AutoMirrored.Filled.ViewList
|
||||
} else {
|
||||
Icons.Filled.ViewModule
|
||||
},
|
||||
onClick = { selectingDisplayMode = true },
|
||||
),
|
||||
)
|
||||
if (isLocalSource) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.label_help),
|
||||
onClick = onHelpClick,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Icons.Filled.ViewModule
|
||||
},
|
||||
onClick = { selectingDisplayMode = true },
|
||||
),
|
||||
if (isLocalSource) {
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.label_help),
|
||||
onClick = onHelpClick,
|
||||
)
|
||||
} else {
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_open_in_web_view),
|
||||
onClick = onWebViewClick,
|
||||
)
|
||||
},
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_settings),
|
||||
onClick = onSettingsClick,
|
||||
).takeIf { isConfigurableSource },
|
||||
),
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_open_in_web_view),
|
||||
onClick = onWebViewClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (isConfigurableSource) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_settings),
|
||||
onClick = onSettingsClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
.build(),
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
|
|
|
@ -58,7 +58,7 @@ fun GlobalAnimeSearchToolbar(
|
|||
)
|
||||
if (progress in 1..<total) {
|
||||
LinearProgressIndicator(
|
||||
progress = progress / total.toFloat(),
|
||||
progress = { progress / total.toFloat() },
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomStart)
|
||||
.fillMaxWidth(),
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.Public
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
|
@ -24,6 +25,7 @@ import eu.kanade.presentation.components.AppBar
|
|||
import eu.kanade.presentation.util.formattedMessage
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.MangaSource
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||
|
@ -76,15 +78,15 @@ fun BrowseSourceContent(
|
|||
modifier = Modifier.padding(contentPadding),
|
||||
message = getErrorMessage(errorState),
|
||||
actions = if (source is LocalMangaSource) {
|
||||
listOf(
|
||||
persistentListOf(
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.local_source_help_guide,
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = onLocalSourceHelpClick,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
listOf(
|
||||
persistentListOf(
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.action_retry,
|
||||
icon = Icons.Outlined.Refresh,
|
||||
|
@ -97,7 +99,7 @@ fun BrowseSourceContent(
|
|||
),
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.label_help,
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = onHelpClick,
|
||||
),
|
||||
)
|
||||
|
@ -145,7 +147,7 @@ fun BrowseSourceContent(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun MissingSourceScreen(
|
||||
internal fun MissingSourceScreen(
|
||||
source: StubMangaSource,
|
||||
navigateUp: () -> Unit,
|
||||
) {
|
||||
|
|
|
@ -60,13 +60,13 @@ fun GlobalMangaSearchScreen(
|
|||
|
||||
@Composable
|
||||
internal fun GlobalSearchContent(
|
||||
fromSourceId: Long? = null,
|
||||
items: Map<CatalogueSource, MangaSearchItemResult>,
|
||||
contentPadding: PaddingValues,
|
||||
getManga: @Composable (Manga) -> State<Manga>,
|
||||
onClickSource: (CatalogueSource) -> Unit,
|
||||
onClickItem: (Manga) -> Unit,
|
||||
onLongClickItem: (Manga) -> Unit,
|
||||
fromSourceId: Long? = null,
|
||||
) {
|
||||
LazyColumn(
|
||||
contentPadding = contentPadding,
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.History
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
|
@ -55,6 +56,7 @@ import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
|||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.ui.browse.manga.extension.details.MangaExtensionDetailsScreenModel
|
||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
@ -80,40 +82,42 @@ fun ExtensionDetailsScreen(
|
|||
navigateUp = navigateUp,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
actions = buildList {
|
||||
if (state.extension?.isUnofficial == false) {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.whats_new),
|
||||
icon = Icons.Outlined.History,
|
||||
onClick = onClickWhatsNew,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_faq_and_guides),
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
onClick = onClickReadme,
|
||||
actions = persistentListOf<AppBar.AppBarAction>().builder()
|
||||
.apply {
|
||||
if (state.extension?.isUnofficial == false) {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.whats_new),
|
||||
icon = Icons.Outlined.History,
|
||||
onClick = onClickWhatsNew,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_faq_and_guides),
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = onClickReadme,
|
||||
),
|
||||
)
|
||||
}
|
||||
addAll(
|
||||
listOf(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_enable_all),
|
||||
onClick = onClickEnableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_disable_all),
|
||||
onClick = onClickDisableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.pref_clear_cookies),
|
||||
onClick = onClickClearCookies,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
addAll(
|
||||
listOf(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_enable_all),
|
||||
onClick = onClickEnableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_disable_all),
|
||||
onClick = onClickDisableAll,
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.pref_clear_cookies),
|
||||
onClick = onClickClearCookies,
|
||||
),
|
||||
),
|
||||
)
|
||||
},
|
||||
.build(),
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
|
@ -187,7 +191,7 @@ private fun ExtensionDetails(
|
|||
key = { it.source.id },
|
||||
) { source ->
|
||||
SourceSwitchPreference(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = source,
|
||||
onClickSourcePreferences = onClickSourcePreferences,
|
||||
onClickSource = onClickSource,
|
||||
|
@ -320,10 +324,10 @@ private fun DetailsHeader(
|
|||
|
||||
@Composable
|
||||
private fun InfoText(
|
||||
modifier: Modifier,
|
||||
primaryText: String,
|
||||
primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge,
|
||||
secondaryText: String,
|
||||
modifier: Modifier = Modifier,
|
||||
primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge,
|
||||
onClick: (() -> Unit)? = null,
|
||||
) {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
|
@ -363,10 +367,10 @@ private fun InfoDivider() {
|
|||
|
||||
@Composable
|
||||
private fun SourceSwitchPreference(
|
||||
modifier: Modifier = Modifier,
|
||||
source: MangaExtensionSourceItem,
|
||||
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
||||
onClickSource: (sourceId: Long) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ private fun ExtensionFilterContent(
|
|||
) {
|
||||
items(state.languages) { language ->
|
||||
SwitchPreferenceWidget(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
title = LocaleHelper.getSourceDisplayName(language, context),
|
||||
checked = language in state.enabledLanguages,
|
||||
onCheckedChanged = { onClickLang(language) },
|
||||
|
|
|
@ -148,14 +148,14 @@ private fun ExtensionContent(
|
|||
}
|
||||
ExtensionHeader(
|
||||
textRes = header.textRes,
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
action = action,
|
||||
)
|
||||
}
|
||||
is MangaExtensionUiModel.Header.Text -> {
|
||||
ExtensionHeader(
|
||||
text = header.text,
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ private fun ExtensionContent(
|
|||
key = { "extension-${it.hashCode()}" },
|
||||
) { item ->
|
||||
ExtensionItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
item = item,
|
||||
onClickItem = {
|
||||
when (it) {
|
||||
|
@ -217,12 +217,12 @@ private fun ExtensionContent(
|
|||
|
||||
@Composable
|
||||
private fun ExtensionItem(
|
||||
modifier: Modifier = Modifier,
|
||||
item: MangaExtensionUiModel.Item,
|
||||
onClickItem: (MangaExtension) -> Unit,
|
||||
onLongClickItem: (MangaExtension) -> Unit,
|
||||
onClickItemCancel: (MangaExtension) -> Unit,
|
||||
onClickItemAction: (MangaExtension) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val (extension, installStep) = item
|
||||
BaseBrowseItem(
|
||||
|
|
|
@ -68,7 +68,7 @@ private fun SourcesFilterContent(
|
|||
contentType = "source-filter-header",
|
||||
) {
|
||||
SourcesFilterHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
language = language,
|
||||
enabled = enabled,
|
||||
onClickItem = onClickLanguage,
|
||||
|
@ -81,7 +81,7 @@ private fun SourcesFilterContent(
|
|||
contentType = { "source-filter-item" },
|
||||
) { source ->
|
||||
SourcesFilterItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = source,
|
||||
enabled = "${source.id}" !in state.disabledSources,
|
||||
onClickItem = onClickSource,
|
||||
|
@ -94,10 +94,11 @@ private fun SourcesFilterContent(
|
|||
|
||||
@Composable
|
||||
private fun SourcesFilterHeader(
|
||||
modifier: Modifier,
|
||||
language: String,
|
||||
enabled: Boolean,
|
||||
onClickItem: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
|
||||
) {
|
||||
SwitchPreferenceWidget(
|
||||
modifier = modifier,
|
||||
|
@ -109,10 +110,10 @@ private fun SourcesFilterHeader(
|
|||
|
||||
@Composable
|
||||
private fun SourcesFilterItem(
|
||||
modifier: Modifier,
|
||||
source: Source,
|
||||
enabled: Boolean,
|
||||
onClickItem: (Source) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseMangaSourceItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -74,12 +74,12 @@ fun MangaSourcesScreen(
|
|||
when (model) {
|
||||
is MangaSourceUiModel.Header -> {
|
||||
SourceHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
language = model.language,
|
||||
)
|
||||
}
|
||||
is MangaSourceUiModel.Item -> SourceItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = model.source,
|
||||
onClickItem = onClickItem,
|
||||
onLongClickItem = onLongClickItem,
|
||||
|
@ -94,8 +94,8 @@ fun MangaSourcesScreen(
|
|||
|
||||
@Composable
|
||||
private fun SourceHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
language: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
Text(
|
||||
|
@ -111,11 +111,11 @@ private fun SourceHeader(
|
|||
|
||||
@Composable
|
||||
private fun SourceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
source: Source,
|
||||
onClickItem: (Source, Listing) -> Unit,
|
||||
onLongClickItem: (Source) -> Unit,
|
||||
onClickPin: (Source) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseMangaSourceItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -70,10 +70,10 @@ private fun MigrateMangaContent(
|
|||
|
||||
@Composable
|
||||
private fun MigrateMangaItem(
|
||||
modifier: Modifier = Modifier,
|
||||
manga: Manga,
|
||||
onClickItem: (Manga) -> Unit,
|
||||
onClickCover: (Manga) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseMangaListItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -132,7 +132,7 @@ private fun MigrateSourceList(
|
|||
key = { (source, _) -> "migrate-${source.id}" },
|
||||
) { (source, count) ->
|
||||
MigrateSourceItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
source = source,
|
||||
count = count,
|
||||
onClickItem = { onClickItem(source) },
|
||||
|
@ -144,11 +144,11 @@ private fun MigrateSourceList(
|
|||
|
||||
@Composable
|
||||
private fun MigrateSourceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
source: Source,
|
||||
count: Long,
|
||||
onClickItem: () -> Unit,
|
||||
onLongClickItem: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BaseMangaSourceItem(
|
||||
modifier = modifier,
|
||||
|
|
|
@ -17,8 +17,8 @@ import tachiyomi.presentation.core.util.secondaryItemAlpha
|
|||
|
||||
@Composable
|
||||
fun BaseMangaSourceItem(
|
||||
modifier: Modifier = Modifier,
|
||||
source: Source,
|
||||
modifier: Modifier = Modifier,
|
||||
showLanguageInContent: Boolean = true,
|
||||
onClickItem: () -> Unit = {},
|
||||
onLongClickItem: () -> Unit = {},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.presentation.browse.manga.components
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ViewList
|
||||
import androidx.compose.material.icons.filled.ViewList
|
||||
import androidx.compose.material.icons.filled.ViewModule
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -20,6 +21,7 @@ import eu.kanade.presentation.components.SearchToolbar
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.MangaSource
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||
import tachiyomi.source.local.entries.manga.LocalMangaSource
|
||||
|
||||
|
@ -53,32 +55,44 @@ fun BrowseMangaSourceToolbar(
|
|||
onClickCloseSearch = navigateUp,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
actions = listOfNotNull(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_display_mode),
|
||||
icon = if (displayMode == LibraryDisplayMode.List) {
|
||||
Icons.Filled.ViewList
|
||||
actions = persistentListOf<AppBar.AppBarAction>().builder()
|
||||
.apply {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_display_mode),
|
||||
icon = if (displayMode == LibraryDisplayMode.List) {
|
||||
Icons.AutoMirrored.Filled.ViewList
|
||||
} else {
|
||||
Icons.Filled.ViewModule
|
||||
},
|
||||
onClick = { selectingDisplayMode = true },
|
||||
),
|
||||
)
|
||||
if (isLocalSource) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.label_help),
|
||||
onClick = onHelpClick,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Icons.Filled.ViewModule
|
||||
},
|
||||
onClick = { selectingDisplayMode = true },
|
||||
),
|
||||
if (isLocalSource) {
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.label_help),
|
||||
onClick = onHelpClick,
|
||||
)
|
||||
} else {
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_open_in_web_view),
|
||||
onClick = onWebViewClick,
|
||||
)
|
||||
},
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_settings),
|
||||
onClick = onSettingsClick,
|
||||
).takeIf { isConfigurableSource },
|
||||
),
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_open_in_web_view),
|
||||
onClick = onWebViewClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (isConfigurableSource) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_settings),
|
||||
onClick = onSettingsClick,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
.build(),
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
|
|
|
@ -7,7 +7,6 @@ import androidx.compose.foundation.lazy.LazyListState
|
|||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
||||
|
@ -32,7 +31,7 @@ fun CategoryContent(
|
|||
key = { _, category -> "category-${category.id}" },
|
||||
) { index, category ->
|
||||
CategoryListItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
category = category,
|
||||
canMoveUp = index != 0,
|
||||
canMoveDown = index != categories.lastIndex,
|
||||
|
|
|
@ -6,6 +6,7 @@ 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.ArrowDropDown
|
||||
import androidx.compose.material.icons.outlined.ArrowDropUp
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
|
@ -28,7 +29,6 @@ import tachiyomi.presentation.core.components.material.padding
|
|||
|
||||
@Composable
|
||||
fun CategoryListItem(
|
||||
modifier: Modifier = Modifier,
|
||||
category: Category,
|
||||
canMoveUp: Boolean,
|
||||
canMoveDown: Boolean,
|
||||
|
@ -37,6 +37,7 @@ fun CategoryListItem(
|
|||
onRename: () -> Unit,
|
||||
onHide: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
ElevatedCard(
|
||||
modifier = modifier,
|
||||
|
@ -52,7 +53,7 @@ fun CategoryListItem(
|
|||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(imageVector = Icons.Outlined.Label, contentDescription = "")
|
||||
Icon(imageVector = Icons.AutoMirrored.Outlined.Label, contentDescription = "")
|
||||
Text(
|
||||
text = category.name,
|
||||
modifier = Modifier
|
||||
|
|
|
@ -73,11 +73,11 @@ fun NavigatorAdaptiveSheet(
|
|||
*/
|
||||
@Composable
|
||||
fun AdaptiveSheet(
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
hideSystemBars: Boolean = false,
|
||||
tonalElevation: Dp = 1.dp,
|
||||
enableSwipeDismiss: Boolean = true,
|
||||
onDismissRequest: () -> Unit,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val isTabletUi = isTabletUi()
|
||||
|
|
|
@ -13,7 +13,7 @@ import androidx.compose.foundation.text.KeyboardActions
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.Close
|
||||
import androidx.compose.material.icons.outlined.MoreVert
|
||||
import androidx.compose.material.icons.outlined.Search
|
||||
|
@ -22,11 +22,14 @@ import androidx.compose.material3.Icon
|
|||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PlainTooltipBox
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
|
@ -52,6 +55,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import tachiyomi.presentation.core.components.Pill
|
||||
import tachiyomi.presentation.core.util.clearFocusOnSoftKeyboardHide
|
||||
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
|
||||
|
@ -205,18 +209,23 @@ fun AppBarTitle(
|
|||
|
||||
@Composable
|
||||
fun AppBarActions(
|
||||
actions: List<AppBar.AppBarAction>,
|
||||
actions: ImmutableList<AppBar.AppBarAction>,
|
||||
) {
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
|
||||
actions.filterIsInstance<AppBar.Action>().map {
|
||||
PlainTooltipBox(
|
||||
tooltip = { Text(it.title) },
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(it.title)
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = it.onClick,
|
||||
enabled = it.enabled,
|
||||
modifier = Modifier.tooltipTrigger(),
|
||||
) {
|
||||
Icon(
|
||||
imageVector = it.icon,
|
||||
|
@ -229,12 +238,17 @@ fun AppBarActions(
|
|||
|
||||
val overflowActions = actions.filterIsInstance<AppBar.OverflowAction>()
|
||||
if (overflowActions.isNotEmpty()) {
|
||||
PlainTooltipBox(
|
||||
tooltip = { Text(stringResource(R.string.abc_action_menu_overflow_description)) },
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(stringResource(R.string.abc_action_menu_overflow_description))
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { showMenu = !showMenu },
|
||||
modifier = Modifier.tooltipTrigger(),
|
||||
) {
|
||||
Icon(
|
||||
Icons.Outlined.MoreVert,
|
||||
|
@ -356,12 +370,17 @@ fun SearchToolbar(
|
|||
if (!searchEnabled) {
|
||||
// Don't show search action
|
||||
} else if (searchQuery == null) {
|
||||
PlainTooltipBox(
|
||||
tooltip = { Text(stringResource(R.string.action_search)) },
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(stringResource(R.string.action_search))
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.tooltipTrigger(),
|
||||
) {
|
||||
Icon(
|
||||
Icons.Outlined.Search,
|
||||
|
@ -370,15 +389,20 @@ fun SearchToolbar(
|
|||
}
|
||||
}
|
||||
} else if (searchQuery.isNotEmpty()) {
|
||||
PlainTooltipBox(
|
||||
tooltip = { Text(stringResource(R.string.action_reset)) },
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(stringResource(R.string.action_reset))
|
||||
}
|
||||
},
|
||||
state = rememberTooltipState(),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
onClick()
|
||||
focusRequester.requestFocus()
|
||||
},
|
||||
modifier = Modifier.tooltipTrigger(),
|
||||
) {
|
||||
Icon(
|
||||
Icons.Outlined.Close,
|
||||
|
@ -400,7 +424,7 @@ fun SearchToolbar(
|
|||
@Composable
|
||||
fun UpIcon(navigationIcon: ImageVector? = null) {
|
||||
val icon = navigationIcon
|
||||
?: Icons.Outlined.ArrowBack
|
||||
?: Icons.AutoMirrored.Outlined.ArrowBack
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
||||
|
|
|
@ -3,7 +3,7 @@ package eu.kanade.presentation.components
|
|||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ArrowLeft
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowRight
|
||||
import androidx.compose.material.icons.outlined.ArrowRight
|
||||
import androidx.compose.material.icons.outlined.RadioButtonChecked
|
||||
import androidx.compose.material.icons.outlined.RadioButtonUnchecked
|
||||
|
@ -84,7 +84,7 @@ fun NestedMenuItem(
|
|||
onClick = { nestedExpanded = true },
|
||||
trailingIcon = {
|
||||
Icon(
|
||||
imageVector = if (isLtr) Icons.Outlined.ArrowRight else Icons.Outlined.ArrowLeft,
|
||||
imageVector = Icons.AutoMirrored.Outlined.ArrowRight,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.kanade.presentation.components
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.Refresh
|
||||
import androidx.compose.material3.Surface
|
||||
|
@ -8,6 +9,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
||||
|
||||
|
@ -30,7 +32,7 @@ private fun WithActionPreview() {
|
|||
Surface {
|
||||
EmptyScreen(
|
||||
textResource = R.string.empty_screen,
|
||||
actions = listOf(
|
||||
actions = persistentListOf(
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.action_retry,
|
||||
icon = Icons.Outlined.Refresh,
|
||||
|
@ -38,7 +40,7 @@ private fun WithActionPreview() {
|
|||
),
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.getting_started_guide,
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = {},
|
||||
),
|
||||
),
|
||||
|
|
|
@ -11,10 +11,10 @@ import java.util.Date
|
|||
|
||||
@Composable
|
||||
fun RelativeDateHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
date: Date,
|
||||
relativeTime: Boolean,
|
||||
dateFormat: DateFormat,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
ListGroupHeader(
|
||||
|
|
|
@ -14,8 +14,8 @@ import androidx.compose.material3.HorizontalDivider
|
|||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PrimaryTabRow
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
|
@ -29,9 +29,9 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.util.fastForEachIndexed
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.HorizontalPager
|
||||
import tachiyomi.presentation.core.components.material.TabIndicator
|
||||
import tachiyomi.presentation.core.components.material.TabText
|
||||
|
||||
object TabbedDialogPaddings {
|
||||
|
@ -41,9 +41,9 @@ object TabbedDialogPaddings {
|
|||
|
||||
@Composable
|
||||
fun TabbedDialog(
|
||||
modifier: Modifier = Modifier,
|
||||
onDismissRequest: () -> Unit,
|
||||
tabTitles: List<String>,
|
||||
tabTitles: ImmutableList<String>,
|
||||
modifier: Modifier = Modifier,
|
||||
tabOverflowMenuContent: (@Composable ColumnScope.(() -> Unit) -> Unit)? = null,
|
||||
onOverflowMenuClicked: (() -> Unit)? = null,
|
||||
overflowIcon: ImageVector? = null,
|
||||
|
@ -60,15 +60,9 @@ fun TabbedDialog(
|
|||
|
||||
Column {
|
||||
Row {
|
||||
TabRow(
|
||||
PrimaryTabRow(
|
||||
modifier = Modifier.weight(1f),
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
indicator = {
|
||||
TabIndicator(
|
||||
it[pagerState.currentPage],
|
||||
pagerState.currentPageOffsetFraction,
|
||||
)
|
||||
},
|
||||
divider = {},
|
||||
) {
|
||||
tabTitles.fastForEachIndexed { index, tab ->
|
||||
|
|
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PrimaryTabRow
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
|
@ -25,16 +26,17 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.HorizontalPager
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.TabIndicator
|
||||
import tachiyomi.presentation.core.components.material.TabText
|
||||
|
||||
@Composable
|
||||
fun TabbedScreen(
|
||||
@StringRes titleRes: Int?,
|
||||
tabs: List<TabContent>,
|
||||
tabs: ImmutableList<TabContent>,
|
||||
startIndex: Int? = null,
|
||||
mangaSearchQuery: String? = null,
|
||||
onChangeMangaSearchQuery: (String?) -> Unit = {},
|
||||
|
@ -89,10 +91,8 @@ fun TabbedScreen(
|
|||
end = contentPadding.calculateEndPadding(LocalLayoutDirection.current),
|
||||
),
|
||||
) {
|
||||
FlexibleTabRow(
|
||||
scrollable = scrollable,
|
||||
PrimaryTabRow(
|
||||
selectedTabIndex = state.currentPage,
|
||||
indicator = { TabIndicator(it[state.currentPage], state.currentPageOffsetFraction) },
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
|
@ -127,7 +127,7 @@ data class TabContent(
|
|||
@StringRes val titleRes: Int,
|
||||
val badgeNumber: Int? = null,
|
||||
val searchEnabled: Boolean = false,
|
||||
val actions: List<AppBar.Action> = emptyList(),
|
||||
val actions: ImmutableList<AppBar.Action> = persistentListOf(),
|
||||
val content: @Composable (contentPadding: PaddingValues, snackbarHostState: SnackbarHostState) -> Unit,
|
||||
val numberTitle: Int = 0,
|
||||
val cancelAction: () -> Unit = {},
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.size
|
|||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.shape.ZeroCornerSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.Label
|
||||
import androidx.compose.material.icons.outlined.BookmarkAdd
|
||||
import androidx.compose.material.icons.outlined.BookmarkRemove
|
||||
import androidx.compose.material.icons.outlined.Delete
|
||||
|
@ -304,7 +305,7 @@ fun LibraryBottomActionMenu(
|
|||
) {
|
||||
Button(
|
||||
title = stringResource(R.string.action_move_category),
|
||||
icon = Icons.Outlined.Label,
|
||||
icon = Icons.AutoMirrored.Outlined.Label,
|
||||
toConfirm = confirm[0],
|
||||
onLongClick = { onLongClickItem(0) },
|
||||
onClick = onChangeCategoryClicked,
|
||||
|
|
|
@ -29,6 +29,7 @@ import eu.kanade.presentation.components.AppBarActions
|
|||
import eu.kanade.presentation.components.EntryDownloadDropdownMenu
|
||||
import eu.kanade.presentation.components.UpIcon
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.theme.active
|
||||
|
||||
@Composable
|
||||
|
@ -75,7 +76,7 @@ fun EntryToolbar(
|
|||
actions = {
|
||||
if (isActionMode) {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_select_all),
|
||||
icon = Icons.Outlined.SelectAll,
|
||||
|
@ -102,71 +103,65 @@ fun EntryToolbar(
|
|||
|
||||
val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current
|
||||
AppBarActions(
|
||||
actions = buildList {
|
||||
if (onClickDownload != null) {
|
||||
actions = persistentListOf<AppBar.AppBarAction>().builder()
|
||||
.apply {
|
||||
if (onClickDownload != null) {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.manga_download),
|
||||
icon = Icons.Outlined.Download,
|
||||
onClick = { downloadExpanded = !downloadExpanded },
|
||||
),
|
||||
)
|
||||
}
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.manga_download),
|
||||
icon = Icons.Outlined.Download,
|
||||
onClick = { downloadExpanded = !downloadExpanded },
|
||||
title = stringResource(R.string.action_filter),
|
||||
icon = Icons.Outlined.FilterList,
|
||||
iconTint = filterTint,
|
||||
onClick = onClickFilter,
|
||||
),
|
||||
)
|
||||
}
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_filter),
|
||||
icon = Icons.Outlined.FilterList,
|
||||
iconTint = filterTint,
|
||||
onClick = onClickFilter,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_webview_refresh),
|
||||
onClick = onClickRefresh,
|
||||
),
|
||||
)
|
||||
if (onClickEditCategory != null) {
|
||||
if (changeAnimeSkipIntro != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_change_intro_length),
|
||||
onClick = changeAnimeSkipIntro,
|
||||
),
|
||||
)
|
||||
}
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_edit_categories),
|
||||
onClick = onClickEditCategory,
|
||||
title = stringResource(R.string.action_webview_refresh),
|
||||
onClick = onClickRefresh,
|
||||
),
|
||||
)
|
||||
if (onClickEditCategory != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_edit_categories),
|
||||
onClick = onClickEditCategory,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (onClickMigrate != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_migrate),
|
||||
onClick = onClickMigrate,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (onClickShare != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_share),
|
||||
onClick = onClickShare,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
if (onClickMigrate != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_migrate),
|
||||
onClick = onClickMigrate,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (changeAnimeSkipIntro != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_change_intro_length),
|
||||
onClick = changeAnimeSkipIntro,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (onClickSettings != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.settings),
|
||||
onClick = onClickSettings,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (onClickShare != null) {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_share),
|
||||
onClick = onClickShare,
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||
|
||||
@Composable
|
||||
|
@ -68,16 +69,18 @@ fun SetIntervalDialog(
|
|||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
val size = DpSize(width = maxWidth / 2, height = 128.dp)
|
||||
val items = (0..28).map {
|
||||
if (it == 0) {
|
||||
stringResource(R.string.label_default)
|
||||
} else {
|
||||
it.toString()
|
||||
val items = (0..28)
|
||||
.map {
|
||||
if (it == 0) {
|
||||
stringResource(R.string.label_default)
|
||||
} else {
|
||||
it.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
.toImmutableList()
|
||||
WheelTextPicker(
|
||||
size = size,
|
||||
items = items,
|
||||
size = size,
|
||||
startIndex = selectedInterval,
|
||||
onSelectionChanged = { selectedInterval = it },
|
||||
)
|
||||
|
|
|
@ -88,7 +88,6 @@ import tachiyomi.presentation.core.components.VerticalFastScroller
|
|||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||
import tachiyomi.presentation.core.components.material.PullRefresh
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrollingUp
|
||||
import java.text.DateFormat
|
||||
|
@ -350,12 +349,12 @@ private fun AnimeScreenSmallImpl(
|
|||
onClickEditCategory = onEditCategoryClicked,
|
||||
onClickRefresh = onRefresh,
|
||||
onClickMigrate = onMigrateClicked,
|
||||
onClickSettings = onSettingsClicked,
|
||||
changeAnimeSkipIntro = changeAnimeSkipIntro,
|
||||
actionModeCounter = selectedEpisodeCount,
|
||||
onSelectAll = { onAllEpisodeSelected(true) },
|
||||
onInvertSelection = { onInvertSelection() },
|
||||
isManga = false,
|
||||
onClickSettings = onSettingsClicked,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
@ -647,12 +646,12 @@ fun AnimeScreenLargeImpl(
|
|||
onClickEditCategory = onEditCategoryClicked,
|
||||
onClickRefresh = onRefresh,
|
||||
onClickMigrate = onMigrateClicked,
|
||||
onClickSettings = onSettingsClicked,
|
||||
changeAnimeSkipIntro = changeAnimeSkipIntro,
|
||||
actionModeCounter = selectedEpisodeCount,
|
||||
onSelectAll = { onAllEpisodeSelected(true) },
|
||||
onInvertSelection = { onInvertSelection() },
|
||||
isManga = false,
|
||||
onClickSettings = onSettingsClicked,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
|
@ -22,6 +22,7 @@ import eu.kanade.domain.entries.anime.model.forceDownloaded
|
|||
import eu.kanade.presentation.components.TabbedDialog
|
||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.core.preference.TriState
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
|
@ -50,7 +51,7 @@ fun EpisodeSettingsDialog(
|
|||
|
||||
TabbedDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
tabTitles = listOf(
|
||||
tabTitles = persistentListOf(
|
||||
stringResource(R.string.action_filter),
|
||||
stringResource(R.string.action_sort),
|
||||
stringResource(R.string.action_display),
|
||||
|
|
|
@ -49,6 +49,7 @@ import eu.kanade.presentation.components.DropdownMenu
|
|||
import eu.kanade.presentation.entries.EditCoverAction
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
|
@ -91,22 +92,18 @@ fun AnimeCoverDialog(
|
|||
Spacer(modifier = Modifier.weight(1f))
|
||||
ActionsPill {
|
||||
AppBarActions(
|
||||
actions = buildList {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_share),
|
||||
icon = Icons.Outlined.Share,
|
||||
onClick = onShareClick,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_save),
|
||||
icon = Icons.Outlined.Save,
|
||||
onClick = onSaveClick,
|
||||
),
|
||||
)
|
||||
},
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_share),
|
||||
icon = Icons.Outlined.Share,
|
||||
onClick = onShareClick,
|
||||
),
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_save),
|
||||
icon = Icons.Outlined.Save,
|
||||
onClick = onSaveClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
if (onEditClick != null) {
|
||||
Box {
|
||||
|
|
|
@ -145,7 +145,7 @@ private fun DownloadingIndicator(
|
|||
MaterialTheme.colorScheme.background
|
||||
}
|
||||
CircularProgressIndicator(
|
||||
progress = animatedProgress,
|
||||
progress = { animatedProgress },
|
||||
modifier = IndicatorModifier,
|
||||
color = strokeColor,
|
||||
strokeWidth = IndicatorSize / 2,
|
||||
|
|
|
@ -31,6 +31,7 @@ import eu.kanade.domain.entries.manga.model.forceDownloaded
|
|||
import eu.kanade.presentation.components.TabbedDialog
|
||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.core.preference.TriState
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
|
@ -63,7 +64,7 @@ fun ChapterSettingsDialog(
|
|||
|
||||
TabbedDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
tabTitles = listOf(
|
||||
tabTitles = persistentListOf(
|
||||
stringResource(R.string.action_filter),
|
||||
stringResource(R.string.action_sort),
|
||||
stringResource(R.string.action_display),
|
||||
|
|
|
@ -81,7 +81,6 @@ import tachiyomi.presentation.core.components.VerticalFastScroller
|
|||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||
import tachiyomi.presentation.core.components.material.PullRefresh
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrollingUp
|
||||
import java.text.DateFormat
|
||||
|
@ -330,12 +329,12 @@ private fun MangaScreenSmallImpl(
|
|||
onClickEditCategory = onEditCategoryClicked,
|
||||
onClickRefresh = onRefresh,
|
||||
onClickMigrate = onMigrateClicked,
|
||||
onClickSettings = onSettingsClicked,
|
||||
changeAnimeSkipIntro = null,
|
||||
actionModeCounter = selectedChapterCount,
|
||||
onSelectAll = { onAllChapterSelected(true) },
|
||||
onInvertSelection = { onInvertSelection() },
|
||||
isManga = true,
|
||||
onClickSettings = onSettingsClicked,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
@ -588,12 +587,12 @@ fun MangaScreenLargeImpl(
|
|||
onClickEditCategory = onEditCategoryClicked,
|
||||
onClickRefresh = onRefresh,
|
||||
onClickMigrate = onMigrateClicked,
|
||||
onClickSettings = onSettingsClicked,
|
||||
changeAnimeSkipIntro = null,
|
||||
actionModeCounter = selectedChapterCount,
|
||||
onSelectAll = { onAllChapterSelected(true) },
|
||||
onInvertSelection = { onInvertSelection() },
|
||||
isManga = true,
|
||||
onClickSettings = onSettingsClicked,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
|
|
@ -144,7 +144,7 @@ private fun DownloadingIndicator(
|
|||
MaterialTheme.colorScheme.background
|
||||
}
|
||||
CircularProgressIndicator(
|
||||
progress = animatedProgress,
|
||||
progress = { animatedProgress },
|
||||
modifier = IndicatorModifier,
|
||||
color = strokeColor,
|
||||
strokeWidth = IndicatorSize / 2,
|
||||
|
|
|
@ -49,6 +49,7 @@ import eu.kanade.presentation.components.DropdownMenu
|
|||
import eu.kanade.presentation.entries.EditCoverAction
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderPageImageView
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.util.clickableNoIndication
|
||||
|
@ -91,22 +92,18 @@ fun MangaCoverDialog(
|
|||
Spacer(modifier = Modifier.weight(1f))
|
||||
ActionsPill {
|
||||
AppBarActions(
|
||||
actions = buildList {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_share),
|
||||
icon = Icons.Outlined.Share,
|
||||
onClick = onShareClick,
|
||||
),
|
||||
)
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_save),
|
||||
icon = Icons.Outlined.Save,
|
||||
onClick = onSaveClick,
|
||||
),
|
||||
)
|
||||
},
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_share),
|
||||
icon = Icons.Outlined.Share,
|
||||
onClick = onShareClick,
|
||||
),
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_save),
|
||||
icon = Icons.Outlined.Save,
|
||||
onClick = onSaveClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
if (onEditClick != null) {
|
||||
Box {
|
||||
|
|
|
@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.RelativeDateHeader
|
||||
import tachiyomi.domain.history.anime.model.AnimeHistoryWithRelations
|
||||
|
@ -38,7 +37,7 @@ fun AnimeHistoryContent(
|
|||
when (item) {
|
||||
is AnimeHistoryUiModel.Header -> {
|
||||
RelativeDateHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
date = item.date,
|
||||
relativeTime = relativeTime,
|
||||
dateFormat = dateFormat,
|
||||
|
@ -47,7 +46,7 @@ fun AnimeHistoryContent(
|
|||
is AnimeHistoryUiModel.Item -> {
|
||||
val value = item.item
|
||||
AnimeHistoryItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
history = value,
|
||||
onClickCover = { onClickCover(value) },
|
||||
onClickResume = { onClickResume(value) },
|
||||
|
|
|
@ -35,11 +35,11 @@ private val HistoryItemHeight = 96.dp
|
|||
|
||||
@Composable
|
||||
fun AnimeHistoryItem(
|
||||
modifier: Modifier = Modifier,
|
||||
history: AnimeHistoryWithRelations,
|
||||
onClickCover: () -> Unit,
|
||||
onClickResume: () -> Unit,
|
||||
onClickDelete: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package eu.kanade.presentation.history.anime
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import java.time.Instant
|
||||
import java.util.Date
|
||||
|
||||
object AnimeHistoryUiModelProviders {
|
||||
|
||||
class HeadNow : PreviewParameterProvider<AnimeHistoryUiModel> {
|
||||
override val values: Sequence<AnimeHistoryUiModel> =
|
||||
sequenceOf(AnimeHistoryUiModel.Header(Date.from(Instant.now())))
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.components.RelativeDateHeader
|
||||
import tachiyomi.domain.history.manga.model.MangaHistoryWithRelations
|
||||
|
@ -39,7 +38,6 @@ fun MangaHistoryContent(
|
|||
when (item) {
|
||||
is MangaHistoryUiModel.Header -> {
|
||||
RelativeDateHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
date = item.date,
|
||||
relativeTime = relativeTime,
|
||||
dateFormat = dateFormat,
|
||||
|
@ -48,7 +46,6 @@ fun MangaHistoryContent(
|
|||
is MangaHistoryUiModel.Item -> {
|
||||
val value = item.item
|
||||
MangaHistoryItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
history = value,
|
||||
onClickCover = { onClickCover(value) },
|
||||
onClickResume = { onClickResume(value) },
|
||||
|
|
|
@ -35,11 +35,11 @@ private val HISTORY_ITEM_HEIGHT = 96.dp
|
|||
|
||||
@Composable
|
||||
fun MangaHistoryItem(
|
||||
modifier: Modifier = Modifier,
|
||||
history: MangaHistoryWithRelations,
|
||||
onClickCover: () -> Unit,
|
||||
onClickResume: () -> Unit,
|
||||
onClickDelete: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package eu.kanade.presentation.history.manga
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import java.time.Instant
|
||||
import java.util.Date
|
||||
|
||||
object MangaHistoryUiModelProviders {
|
||||
|
||||
class HeadNow : PreviewParameterProvider<MangaHistoryUiModel> {
|
||||
override val values: Sequence<MangaHistoryUiModel> =
|
||||
sequenceOf(MangaHistoryUiModel.Header(Date.from(Instant.now())))
|
||||
}
|
||||
}
|
|
@ -33,11 +33,13 @@ import androidx.compose.ui.draw.drawBehind
|
|||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shadow
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import eu.kanade.presentation.entries.ItemCover
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.domain.entries.EntryCover
|
||||
import tachiyomi.presentation.core.components.BadgeGroup
|
||||
import tachiyomi.presentation.core.util.selectedBackground
|
||||
|
@ -377,7 +379,7 @@ private fun ContinueViewingButton(
|
|||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.PlayArrow,
|
||||
contentDescription = "",
|
||||
contentDescription = stringResource(R.string.action_resume),
|
||||
modifier = Modifier.size(16.dp),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,13 +4,12 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ScrollableTabRow
|
||||
import androidx.compose.material3.PrimaryScrollableTabRow
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.category.visualName
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.presentation.core.components.material.TabIndicator
|
||||
import tachiyomi.presentation.core.components.material.TabText
|
||||
|
||||
@Composable
|
||||
|
@ -21,15 +20,9 @@ fun LibraryTabs(
|
|||
onTabItemClick: (Int) -> Unit,
|
||||
) {
|
||||
Column {
|
||||
ScrollableTabRow(
|
||||
PrimaryScrollableTabRow(
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
edgePadding = 0.dp,
|
||||
indicator = {
|
||||
TabIndicator(
|
||||
it[pagerState.currentPage],
|
||||
pagerState.currentPageOffsetFraction,
|
||||
)
|
||||
},
|
||||
// TODO: use default when width is fixed upstream
|
||||
// https://issuetracker.google.com/issues/242879624
|
||||
divider = {},
|
||||
|
|
|
@ -21,6 +21,7 @@ import eu.kanade.presentation.components.AppBar
|
|||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.components.SearchToolbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.components.Pill
|
||||
import tachiyomi.presentation.core.theme.active
|
||||
|
||||
|
@ -99,7 +100,7 @@ fun LibraryRegularToolbar(
|
|||
actions = {
|
||||
val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_filter),
|
||||
icon = Icons.Outlined.FilterList,
|
||||
|
@ -138,7 +139,7 @@ fun LibrarySelectionToolbar(
|
|||
titleContent = { Text(text = "$selectedCount") },
|
||||
actions = {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_select_all),
|
||||
icon = Icons.Outlined.SelectAll,
|
||||
|
|
|
@ -18,6 +18,7 @@ import eu.kanade.presentation.components.TabbedDialog
|
|||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.library.anime.AnimeLibrarySettingsScreenModel
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.core.preference.TriState
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.library.anime.model.AnimeLibrarySort
|
||||
|
@ -40,7 +41,7 @@ fun AnimeLibrarySettingsDialog(
|
|||
) {
|
||||
TabbedDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
tabTitles = listOf(
|
||||
tabTitles = persistentListOf(
|
||||
stringResource(R.string.action_filter),
|
||||
stringResource(R.string.action_sort),
|
||||
stringResource(R.string.action_display),
|
||||
|
|
|
@ -18,6 +18,7 @@ import eu.kanade.presentation.components.TabbedDialog
|
|||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.library.manga.MangaLibrarySettingsScreenModel
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.core.preference.TriState
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.library.manga.model.MangaLibrarySort
|
||||
|
@ -40,7 +41,7 @@ fun MangaLibrarySettingsDialog(
|
|||
) {
|
||||
TabbedDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
tabTitles = listOf(
|
||||
tabTitles = persistentListOf(
|
||||
stringResource(R.string.action_filter),
|
||||
stringResource(R.string.action_sort),
|
||||
stringResource(R.string.action_display),
|
||||
|
|
|
@ -9,13 +9,14 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.automirrored.outlined.Label
|
||||
import androidx.compose.material.icons.outlined.CloudOff
|
||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||
import androidx.compose.material.icons.outlined.GetApp
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.History
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material.icons.outlined.Label
|
||||
import androidx.compose.material.icons.outlined.QueryStats
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.Storage
|
||||
|
@ -163,7 +164,7 @@ fun MoreScreen(
|
|||
item {
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.general_categories),
|
||||
icon = Icons.Outlined.Label,
|
||||
icon = Icons.AutoMirrored.Outlined.Label,
|
||||
onPreferenceClick = onClickCategories,
|
||||
)
|
||||
}
|
||||
|
@ -208,7 +209,7 @@ fun MoreScreen(
|
|||
item {
|
||||
TextPreferenceWidget(
|
||||
title = stringResource(R.string.label_help),
|
||||
icon = Icons.Outlined.HelpOutline,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onPreferenceClick = { uriHandler.openUri(Constants.URL_HELP) },
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.OpenInNew
|
||||
import androidx.compose.material.icons.automirrored.outlined.OpenInNew
|
||||
import androidx.compose.material.icons.outlined.NewReleases
|
||||
import androidx.compose.material.icons.outlined.OpenInNew
|
||||
import androidx.compose.material3.Icon
|
||||
|
@ -61,7 +61,7 @@ fun NewUpdateScreen(
|
|||
) {
|
||||
Text(text = stringResource(R.string.update_check_open))
|
||||
Spacer(modifier = Modifier.width(MaterialTheme.padding.tiny))
|
||||
Icon(imageVector = Icons.Default.OpenInNew, contentDescription = null)
|
||||
Icon(imageVector = Icons.AutoMirrored.Outlined.OpenInNew, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,12 +85,11 @@ fun PreferenceScreen(
|
|||
private fun List<Preference>.findHighlightedIndex(highlightKey: String): Int {
|
||||
return flatMap {
|
||||
if (it is Preference.PreferenceGroup) {
|
||||
mutableListOf<String?>()
|
||||
.apply {
|
||||
add(null) // Header
|
||||
addAll(it.preferenceItems.map { groupItem -> groupItem.title })
|
||||
add(null) // Spacer
|
||||
}
|
||||
buildList<String?> {
|
||||
add(null) // Header
|
||||
addAll(it.preferenceItems.map { groupItem -> groupItem.title })
|
||||
add(null) // Spacer
|
||||
}
|
||||
} else {
|
||||
listOf(it.title)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.presentation.more.settings.screen
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -13,44 +12,39 @@ import androidx.annotation.StringRes
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.more.settings.Preference
|
||||
import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen
|
||||
import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
|
||||
import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
|
||||
import eu.kanade.presentation.permissions.PermissionRequestHelper
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupConst
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateJob
|
||||
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.cache.EpisodeCache
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.launchNonCancellable
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
|
@ -64,11 +58,7 @@ import tachiyomi.domain.backup.service.FLAG_HISTORY
|
|||
import tachiyomi.domain.backup.service.FLAG_SETTINGS
|
||||
import tachiyomi.domain.backup.service.FLAG_TRACK
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
|
@ -134,140 +124,11 @@ object SettingsDataScreen : SearchableSettings {
|
|||
|
||||
@Composable
|
||||
private fun getCreateBackupPref(): Preference.PreferenceItem.TextPreference {
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
var flag by rememberSaveable { mutableIntStateOf(0) }
|
||||
val chooseBackupDir = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.CreateDocument("application/*"),
|
||||
) {
|
||||
if (it != null) {
|
||||
context.contentResolver.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
|
||||
)
|
||||
BackupCreateJob.startNow(context, it, flag)
|
||||
}
|
||||
flag = 0
|
||||
}
|
||||
var showCreateDialog by rememberSaveable { mutableStateOf(false) }
|
||||
if (showCreateDialog) {
|
||||
CreateBackupDialog(
|
||||
onConfirm = {
|
||||
showCreateDialog = false
|
||||
flag = it
|
||||
try {
|
||||
chooseBackupDir.launch(Backup.getFilename())
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
flag = 0
|
||||
context.toast(R.string.file_picker_error)
|
||||
}
|
||||
},
|
||||
onDismissRequest = { showCreateDialog = false },
|
||||
)
|
||||
}
|
||||
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
return Preference.PreferenceItem.TextPreference(
|
||||
title = stringResource(R.string.pref_create_backup),
|
||||
subtitle = stringResource(R.string.pref_create_backup_summ),
|
||||
onClick = {
|
||||
scope.launch {
|
||||
if (!BackupCreateJob.isManualJobRunning(context)) {
|
||||
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
|
||||
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
|
||||
}
|
||||
showCreateDialog = true
|
||||
} else {
|
||||
context.toast(R.string.backup_in_progress)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CreateBackupDialog(
|
||||
onConfirm: (flag: Int) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
val choices = remember {
|
||||
mapOf(
|
||||
BackupConst.BACKUP_CATEGORY to R.string.general_categories,
|
||||
BackupConst.BACKUP_CHAPTER to R.string.chapters_episodes,
|
||||
BackupConst.BACKUP_TRACK to R.string.track,
|
||||
BackupConst.BACKUP_HISTORY to R.string.history,
|
||||
BackupConst.BACKUP_PREFS to R.string.settings,
|
||||
BackupConst.BACKUP_EXT_PREFS to R.string.extension_settings,
|
||||
BackupConst.BACKUP_EXTENSIONS to R.string.label_extensions,
|
||||
)
|
||||
}
|
||||
val flags = remember {
|
||||
mutableStateListOf(
|
||||
BackupConst.BACKUP_CATEGORY,
|
||||
BackupConst.BACKUP_CHAPTER,
|
||||
BackupConst.BACKUP_TRACK,
|
||||
BackupConst.BACKUP_HISTORY,
|
||||
)
|
||||
}
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = { Text(text = stringResource(R.string.backup_choice)) },
|
||||
text = {
|
||||
Box {
|
||||
val state = rememberLazyListState()
|
||||
ScrollbarLazyColumn(state = state) {
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(R.string.entries),
|
||||
checked = true,
|
||||
onCheckedChange = {},
|
||||
)
|
||||
}
|
||||
choices.forEach { (k, v) ->
|
||||
item {
|
||||
val isSelected = flags.contains(k)
|
||||
LabeledCheckbox(
|
||||
label = stringResource(v),
|
||||
checked = isSelected,
|
||||
onCheckedChange = {
|
||||
if (it) {
|
||||
flags.add(k)
|
||||
} else {
|
||||
flags.remove(k)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!state.isScrolledToStart()) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
)
|
||||
}
|
||||
if (!state.isScrolledToEnd()) {
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
val flag = flags.fold(initial = 0, operation = { a, b -> a or b })
|
||||
onConfirm(flag)
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_ok))
|
||||
}
|
||||
},
|
||||
onClick = { navigator.push(CreateBackupScreen()) },
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -362,7 +223,7 @@ object SettingsDataScreen : SearchableSettings {
|
|||
},
|
||||
) {
|
||||
if (it == null) {
|
||||
error = InvalidRestore(message = context.getString(R.string.file_null_uri_error))
|
||||
context.toast(R.string.file_null_uri_error)
|
||||
return@rememberLauncherForActivityResult
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
|||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ChromeReaderMode
|
||||
import androidx.compose.material.icons.outlined.ChromeReaderMode
|
||||
import androidx.compose.material.icons.outlined.Code
|
||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||
|
@ -47,6 +48,7 @@ import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
|||
import eu.kanade.presentation.util.LocalBackPress
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import cafe.adriel.voyager.core.screen.Screen as VoyagerScreen
|
||||
|
||||
|
@ -87,7 +89,7 @@ object SettingsMainScreen : Screen() {
|
|||
navigateUp = backPress::invoke,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_search),
|
||||
icon = Icons.Outlined.Search,
|
||||
|
@ -188,7 +190,7 @@ object SettingsMainScreen : Screen() {
|
|||
Item(
|
||||
titleRes = R.string.pref_category_reader,
|
||||
subtitleRes = R.string.pref_reader_summary,
|
||||
icon = Icons.Outlined.ChromeReaderMode,
|
||||
icon = Icons.AutoMirrored.Outlined.ChromeReaderMode,
|
||||
screen = SettingsReaderScreen,
|
||||
),
|
||||
Item(
|
||||
|
|
|
@ -36,6 +36,7 @@ import eu.kanade.tachiyomi.ui.player.VLC_PLAYER
|
|||
import eu.kanade.tachiyomi.ui.player.WEB_VIDEO_CASTER
|
||||
import eu.kanade.tachiyomi.ui.player.X_PLAYER
|
||||
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
@ -395,7 +396,7 @@ object SettingsPlayerScreen : SearchableSettings {
|
|||
R.string.seconds_short,
|
||||
it,
|
||||
)
|
||||
},
|
||||
}.toImmutableList(),
|
||||
onSelectionChanged = {
|
||||
newLength = it
|
||||
},
|
||||
|
|
|
@ -20,6 +20,7 @@ import eu.kanade.presentation.components.AppBar
|
|||
import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
||||
class OpenSourceLibraryLicenseScreen(
|
||||
|
@ -41,7 +42,7 @@ class OpenSourceLibraryLicenseScreen(
|
|||
actions = {
|
||||
if (!website.isNullOrEmpty()) {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.website),
|
||||
icon = Icons.Default.Public,
|
||||
|
|
|
@ -41,6 +41,7 @@ import eu.kanade.presentation.components.AppBarActions
|
|||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
|
@ -106,7 +107,7 @@ class ClearAnimeDatabaseScreen : Screen() {
|
|||
actions = {
|
||||
if (s.items.isNotEmpty()) {
|
||||
AppBarActions(
|
||||
actions = listOf(
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_select_all),
|
||||
icon = Icons.Outlined.SelectAll,
|
||||
|
|
|
@ -41,6 +41,7 @@ import eu.kanade.presentation.components.AppBarActions
|
|||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
|
@ -106,7 +107,7 @@ class ClearDatabaseScreen : Screen() {
|
|||
actions = {
|
||||
if (s.items.isNotEmpty()) {
|
||||
AppBarActions(
|
||||
actions = listOf(
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_select_all),
|
||||
icon = Icons.Outlined.SelectAll,
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
package eu.kanade.presentation.more.settings.screen.data
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateJob
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.PersistentSet
|
||||
import kotlinx.collections.immutable.minus
|
||||
import kotlinx.collections.immutable.plus
|
||||
import kotlinx.collections.immutable.toPersistentSet
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
|
||||
class CreateBackupScreen : Screen() {
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val context = LocalContext.current
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
val model = rememberScreenModel { CreateBackupScreenModel() }
|
||||
val state by model.state.collectAsState()
|
||||
|
||||
val chooseBackupDir = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.CreateDocument("application/*"),
|
||||
) {
|
||||
if (it != null) {
|
||||
context.contentResolver.takePersistableUriPermission(
|
||||
it,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
|
||||
)
|
||||
model.createBackup(context, it)
|
||||
navigator.pop()
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppBar(
|
||||
title = stringResource(R.string.pref_create_backup),
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = it,
|
||||
)
|
||||
},
|
||||
) { contentPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = MaterialTheme.padding.medium),
|
||||
) {
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(R.string.entries),
|
||||
checked = true,
|
||||
onCheckedChange = {},
|
||||
enabled = false,
|
||||
)
|
||||
}
|
||||
BackupChoices.forEach { (k, v) ->
|
||||
item {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(v),
|
||||
checked = state.flags.contains(k),
|
||||
onCheckedChange = {
|
||||
model.toggleFlag(k)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.fillMaxWidth(),
|
||||
onClick = {
|
||||
if (!BackupCreateJob.isManualJobRunning(context)) {
|
||||
if (DeviceUtil.isMiui && DeviceUtil.isMiuiOptimizationDisabled()) {
|
||||
context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG)
|
||||
}
|
||||
try {
|
||||
chooseBackupDir.launch(Backup.getFilename())
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
context.toast(R.string.file_picker_error)
|
||||
}
|
||||
} else {
|
||||
context.toast(R.string.backup_in_progress)
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.action_create),
|
||||
color = MaterialTheme.colorScheme.onPrimary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CreateBackupScreenModel : StateScreenModel<CreateBackupScreenModel.State>(State()) {
|
||||
|
||||
fun toggleFlag(flag: Int) {
|
||||
mutableState.update {
|
||||
if (it.flags.contains(flag)) {
|
||||
it.copy(flags = it.flags - flag)
|
||||
} else {
|
||||
it.copy(flags = it.flags + flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createBackup(context: Context, uri: Uri) {
|
||||
val flags = state.value.flags.fold(initial = 0, operation = { a, b -> a or b })
|
||||
BackupCreateJob.startNow(context, uri, flags)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
data class State(
|
||||
val flags: PersistentSet<Int> = BackupChoices.keys.toPersistentSet(),
|
||||
)
|
||||
}
|
||||
|
||||
private val BackupChoices = mapOf(
|
||||
BackupCreateFlags.BACKUP_CATEGORY to R.string.general_categories,
|
||||
BackupCreateFlags.BACKUP_CHAPTER to R.string.chapters_episodes,
|
||||
BackupCreateFlags.BACKUP_TRACK to R.string.track,
|
||||
BackupCreateFlags.BACKUP_HISTORY to R.string.history,
|
||||
BackupCreateFlags.BACKUP_PREFS to R.string.settings,
|
||||
BackupCreateFlags.BACKUP_EXT_PREFS to R.string.extension_settings,
|
||||
BackupCreateFlags.BACKUP_EXTENSIONS to R.string.label_extensions,
|
||||
)
|
|
@ -21,6 +21,7 @@ import eu.kanade.presentation.util.Screen
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.serialization.protobuf.schema.ProtoBufSchemaGenerator
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
||||
|
@ -48,7 +49,7 @@ class BackupSchemaScreen : Screen() {
|
|||
navigateUp = navigator::pop,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_copy_to_clipboard),
|
||||
icon = Icons.Default.ContentCopy,
|
||||
|
|
|
@ -33,6 +33,7 @@ import eu.kanade.presentation.util.ioCoroutineScope
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import eu.kanade.tachiyomi.util.system.workManager
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
@ -62,7 +63,7 @@ class WorkerInfoScreen : Screen() {
|
|||
navigateUp = navigator::pop,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_copy_to_clipboard),
|
||||
icon = Icons.Default.ContentCopy,
|
||||
|
|
|
@ -29,6 +29,7 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderOrientation
|
|||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingMode
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
private val animationSpec = tween<IntOffset>(200)
|
||||
|
||||
|
@ -98,27 +99,43 @@ fun ReaderAppBars(
|
|||
navigateUp = navigateUp,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
listOfNotNull(
|
||||
AppBar.Action(
|
||||
title = stringResource(
|
||||
if (bookmarked) R.string.action_remove_bookmark else R.string.action_bookmark,
|
||||
),
|
||||
icon = if (bookmarked) Icons.Outlined.Bookmark else Icons.Outlined.BookmarkBorder,
|
||||
onClick = onToggleBookmarked,
|
||||
),
|
||||
onOpenInWebView?.let {
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_open_in_web_view),
|
||||
onClick = it,
|
||||
actions = persistentListOf<AppBar.AppBarAction>().builder()
|
||||
.apply {
|
||||
add(
|
||||
AppBar.Action(
|
||||
title = stringResource(
|
||||
if (bookmarked) {
|
||||
R.string.action_remove_bookmark
|
||||
} else {
|
||||
R.string.action_bookmark
|
||||
},
|
||||
),
|
||||
icon = if (bookmarked) {
|
||||
Icons.Outlined.Bookmark
|
||||
} else {
|
||||
Icons.Outlined.BookmarkBorder
|
||||
},
|
||||
onClick = onToggleBookmarked,
|
||||
),
|
||||
)
|
||||
},
|
||||
onShare?.let {
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_share),
|
||||
onClick = it,
|
||||
)
|
||||
},
|
||||
),
|
||||
onOpenInWebView?.let {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_open_in_web_view),
|
||||
onClick = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
onShare?.let {
|
||||
add(
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_share),
|
||||
onClick = it,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
.build(),
|
||||
)
|
||||
},
|
||||
)
|
||||
|
|
|
@ -17,6 +17,7 @@ import eu.kanade.presentation.components.TabbedDialog
|
|||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
@Composable
|
||||
fun ReaderSettingsDialog(
|
||||
|
@ -25,7 +26,7 @@ fun ReaderSettingsDialog(
|
|||
onHideMenus: () -> Unit,
|
||||
screenModel: ReaderSettingsScreenModel,
|
||||
) {
|
||||
val tabTitles = listOf(
|
||||
val tabTitles = persistentListOf(
|
||||
stringResource(R.string.pref_category_reading_mode),
|
||||
stringResource(R.string.pref_category_general),
|
||||
stringResource(R.string.custom_filter),
|
||||
|
|
|
@ -36,6 +36,8 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark
|
|||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
|
||||
import tachiyomi.presentation.core.components.WheelNumberPicker
|
||||
import tachiyomi.presentation.core.components.WheelTextPicker
|
||||
|
@ -114,9 +116,9 @@ fun TrackItemSelector(
|
|||
title = stringResource(titleText),
|
||||
content = {
|
||||
WheelNumberPicker(
|
||||
items = range.toImmutableList(),
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
startIndex = selection,
|
||||
items = range.toList(),
|
||||
onSelectionChanged = { onSelectionChange(it) },
|
||||
)
|
||||
},
|
||||
|
@ -129,7 +131,7 @@ fun TrackItemSelector(
|
|||
fun TrackScoreSelector(
|
||||
selection: String,
|
||||
onSelectionChange: (String) -> Unit,
|
||||
selections: List<String>,
|
||||
selections: ImmutableList<String>,
|
||||
onConfirm: () -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
|
@ -137,9 +139,9 @@ fun TrackScoreSelector(
|
|||
title = stringResource(R.string.score),
|
||||
content = {
|
||||
WheelTextPicker(
|
||||
items = selections,
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
startIndex = selections.indexOf(selection).takeIf { it > 0 } ?: (selections.size / 2),
|
||||
items = selections,
|
||||
onSelectionChanged = { onSelectionChange(selections[it]) },
|
||||
)
|
||||
},
|
||||
|
@ -203,9 +205,9 @@ fun TrackDateSelector(
|
|||
fun BaseSelector(
|
||||
title: String,
|
||||
content: @Composable BoxScope.() -> Unit,
|
||||
thirdButton: @Composable (RowScope.() -> Unit)? = null,
|
||||
onConfirm: () -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
thirdButton: @Composable (RowScope.() -> Unit)? = null,
|
||||
) {
|
||||
AlertDialogContent(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.presentation.track.anime
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import eu.kanade.tachiyomi.dev.preview.DummyTracker
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.track.AnimeTrackItem
|
||||
import eu.kanade.test.DummyTracker
|
||||
import tachiyomi.domain.track.anime.model.AnimeTrack
|
||||
import java.text.DateFormat
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.compose.foundation.text.BasicTextField
|
|||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.outlined.ArrowBack
|
||||
import androidx.compose.material3.Button
|
||||
|
@ -81,7 +81,7 @@ fun AnimeTrackerSearch(
|
|||
navigationIcon = {
|
||||
IconButton(onClick = onDismissRequest) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.graphics.Color
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
import eu.kanade.tachiyomi.dev.preview.DummyTracker
|
||||
import eu.kanade.test.DummyTracker
|
||||
|
||||
internal class TrackLogoIconPreviewProvider : PreviewParameterProvider<Tracker> {
|
||||
|
||||
|
|
|
@ -243,10 +243,10 @@ private fun TrackInfoItem(
|
|||
|
||||
@Composable
|
||||
fun TrackDetailsItem(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String?,
|
||||
placeholder: String = "",
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
placeholder: String = "",
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.presentation.track.manga
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import eu.kanade.tachiyomi.dev.preview.DummyTracker
|
||||
import eu.kanade.tachiyomi.ui.entries.manga.track.MangaTrackItem
|
||||
import eu.kanade.test.DummyTracker
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack
|
||||
import java.text.DateFormat
|
||||
|
||||
|
|
|
@ -28,10 +28,9 @@ import androidx.compose.foundation.text.BasicTextField
|
|||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.outlined.ArrowBack
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
|
@ -99,7 +98,7 @@ fun MangaTrackerSearch(
|
|||
navigationIcon = {
|
||||
IconButton(onClick = onDismissRequest) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.ArrowBack,
|
||||
imageVector = Icons.AutoMirrored.Outlined.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
|
|
@ -98,14 +98,14 @@ fun LazyListScope.animeUpdatesUiItems(
|
|||
when (item) {
|
||||
is AnimeUpdatesUiModel.Header -> {
|
||||
ListGroupHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
text = item.date,
|
||||
)
|
||||
}
|
||||
is AnimeUpdatesUiModel.Item -> {
|
||||
val updatesItem = item.item
|
||||
AnimeUpdatesUiItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
update = updatesItem.update,
|
||||
selected = updatesItem.selected,
|
||||
watchProgress = updatesItem.update.lastSecondSeen
|
||||
|
@ -146,7 +146,6 @@ fun LazyListScope.animeUpdatesUiItems(
|
|||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun AnimeUpdatesUiItem(
|
||||
modifier: Modifier,
|
||||
update: AnimeUpdatesWithRelations,
|
||||
selected: Boolean,
|
||||
watchProgress: String?,
|
||||
|
@ -157,6 +156,7 @@ fun AnimeUpdatesUiItem(
|
|||
// Download Indicator
|
||||
downloadStateProvider: () -> AnimeDownload.State,
|
||||
downloadProgressProvider: () -> Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val textAlpha = if (update.seen) ReadItemAlpha else 1f
|
||||
|
|
|
@ -97,14 +97,14 @@ fun LazyListScope.mangaUpdatesUiItems(
|
|||
when (item) {
|
||||
is MangaUpdatesUiModel.Header -> {
|
||||
ListGroupHeader(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
text = item.date,
|
||||
)
|
||||
}
|
||||
is MangaUpdatesUiModel.Item -> {
|
||||
val updatesItem = item.item
|
||||
MangaUpdatesUiItem(
|
||||
modifier = Modifier.animateItemPlacement(),
|
||||
|
||||
update = updatesItem.update,
|
||||
selected = updatesItem.selected,
|
||||
readProgress = updatesItem.update.lastPageRead
|
||||
|
@ -144,7 +144,6 @@ fun LazyListScope.mangaUpdatesUiItems(
|
|||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun MangaUpdatesUiItem(
|
||||
modifier: Modifier,
|
||||
update: MangaUpdatesWithRelations,
|
||||
selected: Boolean,
|
||||
readProgress: String?,
|
||||
|
@ -155,6 +154,7 @@ fun MangaUpdatesUiItem(
|
|||
// Download Indicator
|
||||
downloadStateProvider: () -> MangaDownload.State,
|
||||
downloadProgressProvider: () -> Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
val textAlpha = if (update.read) ReadItemAlpha else 1f
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package eu.kanade.presentation.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.ContentTransform
|
||||
|
@ -27,6 +28,7 @@ import soup.compose.material.motion.animation.rememberSlideDistance
|
|||
/**
|
||||
* For invoking back press to the parent activity
|
||||
*/
|
||||
@SuppressLint("ComposeCompositionLocalUsage")
|
||||
val LocalBackPress: ProvidableCompositionLocal<(() -> Unit)?> = staticCompositionLocalOf { null }
|
||||
|
||||
abstract class Tab : cafe.adriel.voyager.navigator.tab.Tab {
|
||||
|
@ -81,7 +83,7 @@ fun ScreenTransition(
|
|||
targetState = navigator.lastItem,
|
||||
transitionSpec = transition,
|
||||
modifier = modifier,
|
||||
label = "",
|
||||
label = "transition",
|
||||
) { screen ->
|
||||
navigator.saveableState("transition", screen) {
|
||||
content(screen)
|
||||
|
|
|
@ -41,6 +41,7 @@ import eu.kanade.tachiyomi.BuildConfig
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.getHtml
|
||||
import eu.kanade.tachiyomi.util.system.setDefaultSettings
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
|
||||
|
@ -49,11 +50,11 @@ fun WebViewScreenContent(
|
|||
onNavigateUp: () -> Unit,
|
||||
initialTitle: String?,
|
||||
url: String,
|
||||
headers: Map<String, String> = emptyMap(),
|
||||
onUrlChange: (String) -> Unit = {},
|
||||
onShare: (String) -> Unit,
|
||||
onOpenInBrowser: (String) -> Unit,
|
||||
onClearCookies: (String) -> Unit,
|
||||
headers: Map<String, String> = emptyMap(),
|
||||
onUrlChange: (String) -> Unit = {},
|
||||
) {
|
||||
val state = rememberWebViewState(url = url, additionalHttpHeaders = headers)
|
||||
val navigator = rememberWebViewNavigator()
|
||||
|
@ -116,7 +117,7 @@ fun WebViewScreenContent(
|
|||
navigationIcon = Icons.Outlined.Close,
|
||||
actions = {
|
||||
AppBarActions(
|
||||
listOf(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_webview_back),
|
||||
icon = Icons.Outlined.ArrowBack,
|
||||
|
@ -182,7 +183,7 @@ fun WebViewScreenContent(
|
|||
.align(Alignment.BottomCenter),
|
||||
)
|
||||
is LoadingState.Loading -> LinearProgressIndicator(
|
||||
progress = (loadingState as? LoadingState.Loading)?.progress ?: 1f,
|
||||
progress = { (loadingState as? LoadingState.Loading)?.progress ?: 1f },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter),
|
||||
|
|
|
@ -38,6 +38,8 @@ import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
|||
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
||||
import eu.kanade.tachiyomi.data.coil.TachiyomiImageDecoder
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.di.AppModule
|
||||
import eu.kanade.tachiyomi.di.PreferenceModule
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.NetworkPreferences
|
||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||
|
@ -59,8 +61,8 @@ import org.acra.ktx.initAcra
|
|||
import org.acra.sender.HttpSender
|
||||
import org.conscrypt.Conscrypt
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.presentation.widget.entries.anime.TachiyomiAnimeWidgetManager
|
||||
import tachiyomi.presentation.widget.entries.manga.TachiyomiMangaWidgetManager
|
||||
import tachiyomi.presentation.widget.entries.anime.AnimeWidgetManager
|
||||
import tachiyomi.presentation.widget.entries.manga.MangaWidgetManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
@ -134,11 +136,11 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
|||
setAppCompatDelegateThemeMode(Injekt.get<UiPreferences>().themeMode().get())
|
||||
|
||||
// Updates widget update
|
||||
with(TachiyomiMangaWidgetManager(Injekt.get(), Injekt.get())) {
|
||||
with(MangaWidgetManager(Injekt.get(), Injekt.get())) {
|
||||
init(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
}
|
||||
|
||||
with(TachiyomiAnimeWidgetManager(Injekt.get(), Injekt.get())) {
|
||||
with(AnimeWidgetManager(Injekt.get(), Injekt.get())) {
|
||||
init(ProcessLifecycleOwner.get().lifecycleScope)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package eu.kanade.tachiyomi.data.backup
|
||||
|
||||
// Filter options
|
||||
internal object BackupConst {
|
||||
const val BACKUP_CATEGORY = 0x1
|
||||
const val BACKUP_CATEGORY_MASK = 0x1
|
||||
|
||||
const val BACKUP_CHAPTER = 0x2
|
||||
const val BACKUP_CHAPTER_MASK = 0x2
|
||||
|
||||
const val BACKUP_HISTORY = 0x4
|
||||
const val BACKUP_HISTORY_MASK = 0x4
|
||||
|
||||
const val BACKUP_TRACK = 0x8
|
||||
const val BACKUP_TRACK_MASK = 0x8
|
||||
|
||||
const val BACKUP_PREFS = 0x10
|
||||
const val BACKUP_PREFS_MASK = 0x10
|
||||
|
||||
const val BACKUP_EXT_PREFS = 0x20
|
||||
const val BACKUP_EXT_PREFS_MASK = 0x20
|
||||
|
||||
const val BACKUP_EXTENSIONS = 0x40
|
||||
const val BACKUP_EXTENSIONS_MASK = 0x40
|
||||
|
||||
const val BACKUP_ALL = 0x7F
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package eu.kanade.tachiyomi.data.backup
|
||||
|
||||
internal object BackupCreateFlags {
|
||||
const val BACKUP_CATEGORY = 0x1
|
||||
const val BACKUP_CHAPTER = 0x2
|
||||
const val BACKUP_HISTORY = 0x4
|
||||
const val BACKUP_TRACK = 0x8
|
||||
const val BACKUP_PREFS = 0x10
|
||||
const val BACKUP_EXT_PREFS = 0x20
|
||||
const val BACKUP_EXTENSIONS = 0x40
|
||||
|
||||
const val AutomaticDefaults = BACKUP_CATEGORY or
|
||||
BACKUP_CHAPTER or
|
||||
BACKUP_HISTORY or
|
||||
BACKUP_TRACK or
|
||||
BACKUP_PREFS or
|
||||
BACKUP_EXT_PREFS
|
||||
}
|
|
@ -40,7 +40,7 @@ class BackupCreateJob(private val context: Context, workerParams: WorkerParamete
|
|||
val backupPreferences = Injekt.get<BackupPreferences>()
|
||||
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
|
||||
?: backupPreferences.backupsDirectory().get().toUri()
|
||||
val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupConst.BACKUP_ALL)
|
||||
val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupCreateFlags.AutomaticDefaults)
|
||||
try {
|
||||
setForeground(getForegroundInfo())
|
||||
} catch (e: IllegalStateException) {
|
||||
|
|
|
@ -8,6 +8,13 @@ import android.net.Uri
|
|||
import androidx.preference.PreferenceManager
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CATEGORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CHAPTER
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_EXTENSIONS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_EXT_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_HISTORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_TRACK
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupAnime
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupAnimeHistory
|
||||
|
@ -190,7 +197,7 @@ class BackupCreator(
|
|||
*/
|
||||
private suspend fun backupCategories(options: Int): List<BackupCategory> {
|
||||
// Check if user wants category information in backup
|
||||
return if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) {
|
||||
return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
||||
getMangaCategories.await()
|
||||
.filterNot(Category::isSystemCategory)
|
||||
.map(backupCategoryMapper)
|
||||
|
@ -206,7 +213,7 @@ class BackupCreator(
|
|||
*/
|
||||
private suspend fun backupAnimeCategories(options: Int): List<BackupCategory> {
|
||||
// Check if user wants category information in backup
|
||||
return if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) {
|
||||
return if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
||||
getAnimeCategories.await()
|
||||
.filterNot(Category::isSystemCategory)
|
||||
.map(backupCategoryMapper)
|
||||
|
@ -239,7 +246,7 @@ class BackupCreator(
|
|||
val mangaObject = BackupManga.copyFrom(manga)
|
||||
|
||||
// Check if user wants chapter information in backup
|
||||
if (options and BackupConst.BACKUP_CHAPTER_MASK == BackupConst.BACKUP_CHAPTER) {
|
||||
if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) {
|
||||
// Backup all the chapters
|
||||
mangaHandler.awaitList {
|
||||
chaptersQueries.getChaptersByMangaId(
|
||||
|
@ -253,7 +260,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants category information in backup
|
||||
if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) {
|
||||
if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
||||
// Backup categories for this manga
|
||||
val categoriesForManga = getMangaCategories.await(manga.id)
|
||||
if (categoriesForManga.isNotEmpty()) {
|
||||
|
@ -262,7 +269,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants track information in backup
|
||||
if (options and BackupConst.BACKUP_TRACK_MASK == BackupConst.BACKUP_TRACK) {
|
||||
if (options and BACKUP_TRACK == BACKUP_TRACK) {
|
||||
val tracks = mangaHandler.awaitList {
|
||||
manga_syncQueries.getTracksByMangaId(
|
||||
manga.id,
|
||||
|
@ -275,7 +282,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants history information in backup
|
||||
if (options and BackupConst.BACKUP_HISTORY_MASK == BackupConst.BACKUP_HISTORY) {
|
||||
if (options and BACKUP_HISTORY == BACKUP_HISTORY) {
|
||||
val historyByMangaId = getMangaHistory.await(manga.id)
|
||||
if (historyByMangaId.isNotEmpty()) {
|
||||
val history = historyByMangaId.map { history ->
|
||||
|
@ -307,7 +314,7 @@ class BackupCreator(
|
|||
val animeObject = BackupAnime.copyFrom(anime)
|
||||
|
||||
// Check if user wants chapter information in backup
|
||||
if (options and BackupConst.BACKUP_CHAPTER_MASK == BackupConst.BACKUP_CHAPTER) {
|
||||
if (options and BACKUP_CHAPTER == BACKUP_CHAPTER) {
|
||||
// Backup all the chapters
|
||||
val episodes = animeHandler.awaitList {
|
||||
episodesQueries.getEpisodesByAnimeId(
|
||||
|
@ -321,7 +328,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants category information in backup
|
||||
if (options and BackupConst.BACKUP_CATEGORY_MASK == BackupConst.BACKUP_CATEGORY) {
|
||||
if (options and BACKUP_CATEGORY == BACKUP_CATEGORY) {
|
||||
// Backup categories for this manga
|
||||
val categoriesForAnime = getAnimeCategories.await(anime.id)
|
||||
if (categoriesForAnime.isNotEmpty()) {
|
||||
|
@ -330,7 +337,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants track information in backup
|
||||
if (options and BackupConst.BACKUP_TRACK_MASK == BackupConst.BACKUP_TRACK) {
|
||||
if (options and BACKUP_TRACK == BACKUP_TRACK) {
|
||||
val tracks = animeHandler.awaitList {
|
||||
anime_syncQueries.getTracksByAnimeId(
|
||||
anime.id,
|
||||
|
@ -343,7 +350,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
// Check if user wants history information in backup
|
||||
if (options and BackupConst.BACKUP_HISTORY_MASK == BackupConst.BACKUP_HISTORY) {
|
||||
if (options and BACKUP_HISTORY == BACKUP_HISTORY) {
|
||||
val historyByAnimeId = getAnimeHistory.await(anime.id)
|
||||
if (historyByAnimeId.isNotEmpty()) {
|
||||
val history = historyByAnimeId.map { history ->
|
||||
|
@ -364,7 +371,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
private fun backupExtensionPreferences(flags: Int): List<BackupExtensionPreferences> {
|
||||
if (flags and BackupConst.BACKUP_EXT_PREFS_MASK != BackupConst.BACKUP_EXT_PREFS) return emptyList()
|
||||
if (flags and BACKUP_EXT_PREFS != BACKUP_EXT_PREFS) return emptyList()
|
||||
val prefs = mutableListOf<Pair<String, SharedPreferences>>()
|
||||
Injekt.get<AnimeSourceManager>().getCatalogueSources().forEach {
|
||||
val name = it.getPreferenceKey()
|
||||
|
@ -377,14 +384,14 @@ class BackupCreator(
|
|||
return prefs.map {
|
||||
BackupExtensionPreferences(
|
||||
it.first,
|
||||
backupPreferences(it.second, BackupConst.BACKUP_PREFS),
|
||||
backupPreferences(it.second, BACKUP_PREFS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun backupExtensions(flags: Int): List<BackupExtension> {
|
||||
if (flags and BackupConst.BACKUP_EXTENSIONS_MASK != BackupConst.BACKUP_EXTENSIONS) return emptyList()
|
||||
if (flags and BACKUP_EXTENSIONS != BACKUP_EXTENSIONS) return emptyList()
|
||||
val installedExtensions = mutableListOf<BackupExtension>()
|
||||
Injekt.get<AnimeExtensionManager>().installedExtensionsFlow.value.forEach {
|
||||
val packageName = it.pkgName
|
||||
|
@ -416,7 +423,7 @@ class BackupCreator(
|
|||
}
|
||||
|
||||
private fun backupPreferences(prefs: SharedPreferences, flags: Int): List<BackupPreference> {
|
||||
if (flags and BackupConst.BACKUP_PREFS_MASK != BackupConst.BACKUP_PREFS) return emptyList()
|
||||
if (flags and BACKUP_PREFS != BACKUP_PREFS) return emptyList()
|
||||
val backupPreferences = mutableListOf<BackupPreference>()
|
||||
for (pref in prefs.all) {
|
||||
val toAdd = when (pref.value) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import eu.kanade.domain.track.anime.model.toDomainTrack
|
|||
import eu.kanade.tachiyomi.data.database.models.anime.AnimeTrack
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
|
@ -24,7 +25,7 @@ interface AnimeTracker {
|
|||
// Common functions
|
||||
fun getCompletionStatus(): Int
|
||||
|
||||
fun getScoreList(): List<String>
|
||||
fun getScoreList(): ImmutableList<String>
|
||||
|
||||
fun indexToScore(index: Int): Float {
|
||||
return index.toFloat()
|
||||
|
|
|
@ -6,6 +6,7 @@ import eu.kanade.domain.track.manga.model.toDomainTrack
|
|||
import eu.kanade.tachiyomi.data.database.models.manga.MangaTrack
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
|
@ -24,7 +25,7 @@ interface MangaTracker {
|
|||
// Common functions
|
||||
fun getCompletionStatus(): Int
|
||||
|
||||
fun getScoreList(): List<String>
|
||||
fun getScoreList(): ImmutableList<String>
|
||||
|
||||
fun indexToScore(index: Int): Float {
|
||||
return index.toFloat()
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.annotation.CallSuper
|
|||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
interface Tracker {
|
||||
|
@ -25,8 +26,11 @@ interface Tracker {
|
|||
|
||||
@StringRes
|
||||
fun getStatus(status: Int): Int?
|
||||
|
||||
fun getCompletionStatus(): Int
|
||||
fun getScoreList(): List<String>
|
||||
|
||||
fun getScoreList(): ImmutableList<String>
|
||||
|
||||
suspend fun login(username: String, password: String)
|
||||
|
||||
@CallSuper
|
||||
|
|
|
@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
@ -103,18 +106,18 @@ class Anilist(id: Long) :
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
override fun getScoreList(): ImmutableList<String> {
|
||||
return when (scorePreference.get()) {
|
||||
// 10 point
|
||||
POINT_10 -> IntRange(0, 10).map(Int::toString)
|
||||
POINT_10 -> IntRange(0, 10).map(Int::toString).toImmutableList()
|
||||
// 100 point
|
||||
POINT_100 -> IntRange(0, 100).map(Int::toString)
|
||||
POINT_100 -> IntRange(0, 100).map(Int::toString).toImmutableList()
|
||||
// 5 stars
|
||||
POINT_5 -> IntRange(0, 5).map { "$it ★" }
|
||||
POINT_5 -> IntRange(0, 5).map { "$it ★" }.toImmutableList()
|
||||
// Smiley
|
||||
POINT_3 -> listOf("-", "😦", "😐", "😊")
|
||||
POINT_3 -> persistentListOf("-", "😦", "😐", "😊")
|
||||
// 10 point decimal
|
||||
POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() }
|
||||
POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() }.toImmutableList()
|
||||
else -> throw Exception("Unknown score type")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.BaseTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
@ -23,9 +25,7 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi"), MangaTracker, AnimeTracker
|
|||
|
||||
private val api by lazy { BangumiApi(id, client, interceptor) }
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun indexToScore(index: Int): Float {
|
||||
return index.toFloat()
|
||||
|
@ -218,5 +218,9 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi"), MangaTracker, AnimeTracker
|
|||
const val ON_HOLD = 4
|
||||
const val DROPPED = 5
|
||||
const val PLAN_TO_READ = 1
|
||||
|
||||
private val SCORE_LIST = IntRange(0, 10)
|
||||
.map(Int::toString)
|
||||
.toImmutableList()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
|||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.MangaSource
|
||||
import eu.kanade.tachiyomi.source.sourcePreferences
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
import tachiyomi.domain.source.manga.service.MangaSourceManager
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
@ -53,7 +55,7 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedMangaTracker, MangaT
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> = emptyList()
|
||||
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||
|
||||
override fun displayScore(track: MangaTrack): String = ""
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
@ -79,9 +81,9 @@ class Kitsu(id: Long) :
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
override fun getScoreList(): ImmutableList<String> {
|
||||
val df = DecimalFormat("0.#")
|
||||
return listOf("0") + IntRange(2, 20).map { df.format(it / 2f) }
|
||||
return (listOf("0") + IntRange(2, 20).map { df.format(it / 2f) }).toImmutableList()
|
||||
}
|
||||
|
||||
override fun indexToScore(index: Int): Float {
|
||||
|
|
|
@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.track.EnhancedMangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import eu.kanade.tachiyomi.source.MangaSource
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import okhttp3.Dns
|
||||
import okhttp3.OkHttpClient
|
||||
import tachiyomi.domain.entries.manga.model.Manga
|
||||
|
@ -51,7 +53,7 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedMangaTracker, MangaTra
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> = emptyList()
|
||||
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||
|
||||
override suspend fun update(track: MangaTrack, didReadChapter: Boolean): MangaTrack {
|
||||
if (track.status != COMPLETED) {
|
||||
|
|
|
@ -10,6 +10,8 @@ import eu.kanade.tachiyomi.data.track.MangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.copyTo
|
||||
import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), MangaTracker, DeletableMangaTracker {
|
||||
|
||||
|
@ -19,6 +21,12 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), MangaTracker, De
|
|||
const val COMPLETE_LIST = 2
|
||||
const val UNFINISHED_LIST = 3
|
||||
const val ON_HOLD_LIST = 4
|
||||
|
||||
private val SCORE_LIST = (
|
||||
(0..9)
|
||||
.flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0")
|
||||
)
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
private val interceptor by lazy { MangaUpdatesInterceptor(this) }
|
||||
|
@ -49,11 +57,9 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), MangaTracker, De
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETE_LIST
|
||||
|
||||
private val _scoreList = (0..9).flatMap { i -> (0..9).map { j -> "$i.$j" } } + listOf("10.0")
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun getScoreList(): List<String> = _scoreList
|
||||
|
||||
override fun indexToScore(index: Int): Float = _scoreList[index].toFloat()
|
||||
override fun indexToScore(index: Int): Float = SCORE_LIST[index].toFloat()
|
||||
|
||||
override fun displayScore(track: MangaTrack): String = track.score.toString()
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
@ -40,6 +42,10 @@ class MyAnimeList(id: Long) :
|
|||
|
||||
private const val SEARCH_ID_PREFIX = "id:"
|
||||
private const val SEARCH_LIST_PREFIX = "my:"
|
||||
|
||||
private val SCORE_LIST = IntRange(0, 10)
|
||||
.map(Int::toString)
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
@ -85,9 +91,7 @@ class MyAnimeList(id: Long) :
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun indexToScore(index: Int): Float {
|
||||
return index.toFloat()
|
||||
|
|
|
@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.track.DeletableMangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
@ -34,6 +36,10 @@ class Shikimori(id: Long) :
|
|||
const val DROPPED = 4
|
||||
const val PLAN_TO_READ = 5
|
||||
const val REREADING = 6
|
||||
|
||||
private val SCORE_LIST = IntRange(0, 10)
|
||||
.map(Int::toString)
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
@ -42,9 +48,7 @@ class Shikimori(id: Long) :
|
|||
|
||||
private val api by lazy { ShikimoriApi(id, client, interceptor) }
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun indexToScore(index: Int): Float {
|
||||
return index.toFloat()
|
||||
|
|
|
@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.database.models.anime.AnimeTrack
|
|||
import eu.kanade.tachiyomi.data.track.AnimeTracker
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.AnimeTrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
@ -20,6 +22,10 @@ class Simkl(id: Long) : BaseTracker(id, "Simkl"), AnimeTracker {
|
|||
const val ON_HOLD = 3
|
||||
const val NOT_INTERESTING = 4
|
||||
const val PLAN_TO_WATCH = 5
|
||||
|
||||
private val SCORE_LIST = IntRange(0, 10)
|
||||
.map(Int::toString)
|
||||
.toImmutableList()
|
||||
}
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
@ -28,9 +34,7 @@ class Simkl(id: Long) : BaseTracker(id, "Simkl"), AnimeTracker {
|
|||
|
||||
private val api by lazy { SimklApi(client, interceptor) }
|
||||
|
||||
override fun getScoreList(): List<String> {
|
||||
return IntRange(0, 10).map(Int::toString)
|
||||
}
|
||||
override fun getScoreList(): ImmutableList<String> = SCORE_LIST
|
||||
|
||||
override fun displayScore(track: AnimeTrack): String {
|
||||
return track.score.toInt().toString()
|
||||
|
|
|
@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.data.track.EnhancedMangaTracker
|
|||
import eu.kanade.tachiyomi.data.track.MangaTracker
|
||||
import eu.kanade.tachiyomi.data.track.model.MangaTrackSearch
|
||||
import eu.kanade.tachiyomi.source.MangaSource
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.entries.manga.model.Manga as DomainManga
|
||||
import tachiyomi.domain.track.manga.model.MangaTrack as DomainTrack
|
||||
|
||||
|
@ -42,7 +44,7 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedMangaTracker, Ma
|
|||
|
||||
override fun getCompletionStatus(): Int = COMPLETED
|
||||
|
||||
override fun getScoreList(): List<String> = emptyList()
|
||||
override fun getScoreList(): ImmutableList<String> = persistentListOf()
|
||||
|
||||
override fun displayScore(track: MangaTrack): String = ""
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue