mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-27 19:47:51 +02:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
3222247969 | |||
dd6c9ce2fe | |||
7446b28ff1 | |||
38c6702b8f | |||
afcf4b2988 | |||
ebb96a6ff4 | |||
8b0affe9bd | |||
1a25cea0d6 | |||
2ecbcdf4bd | |||
642b392d44 | |||
8dce7b3e9e | |||
33e90d6449 | |||
50b17d5d34 | |||
7818885406 | |||
26af7ccc77 | |||
5d1f79012e | |||
cac80daa71 | |||
fc184f1cfa | |||
725fcbba0e | |||
bdeb209d43 | |||
a078f1ab1b | |||
86c3d8c064 | |||
156191af44 | |||
57bba9e5ab | |||
dd1923fe88 | |||
df773ee15c | |||
f5451a6881 | |||
fcec1581b7 | |||
11cc789e36 | |||
16f9fb2f40 | |||
6bfaa85e84 | |||
8f43fb9530 | |||
04d2a3399b | |||
054bf8ec5d | |||
8417f5a63c | |||
26b46cace0 | |||
0849111247 | |||
f9c25b350e |
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -3,7 +3,7 @@
|
|||||||
I acknowledge that:
|
I acknowledge that:
|
||||||
|
|
||||||
- I have updated:
|
- I have updated:
|
||||||
- To the latest version of the app (stable is v0.14.1)
|
- To the latest version of the app (stable is v0.14.2)
|
||||||
- All extensions
|
- All extensions
|
||||||
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
- I have tried the troubleshooting guide: https://tachiyomi.org/help/guides/troubleshooting-problems/
|
||||||
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
- If this is an issue with an extension, that I should be opening an issue in https://github.com/tachiyomiorg/tachiyomi-extensions
|
||||||
|
4
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
4
.github/ISSUE_TEMPLATE/report_issue.yml
vendored
@ -53,7 +53,7 @@ body:
|
|||||||
label: Tachiyomi version
|
label: Tachiyomi version
|
||||||
description: You can find your Tachiyomi version in **More → About**.
|
description: You can find your Tachiyomi version in **More → About**.
|
||||||
placeholder: |
|
placeholder: |
|
||||||
Example: "0.14.1"
|
Example: "0.14.2"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
|
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated the app to version **[0.14.1](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
- label: I have updated the app to version **[0.14.2](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated all installed extensions.
|
- label: I have updated all installed extensions.
|
||||||
required: true
|
required: true
|
||||||
|
2
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
2
.github/ISSUE_TEMPLATE/request_feature.yml
vendored
@ -33,7 +33,7 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose).
|
||||||
required: true
|
required: true
|
||||||
- label: I have updated the app to version **[0.14.1](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
- label: I have updated the app to version **[0.14.2](https://github.com/tachiyomiorg/tachiyomi/releases/latest)**.
|
||||||
required: true
|
required: true
|
||||||
- label: I will fill out all of the requested information in this form.
|
- label: I will fill out all of the requested information in this form.
|
||||||
required: true
|
required: true
|
||||||
|
@ -27,8 +27,8 @@ android {
|
|||||||
applicationId = "eu.kanade.tachiyomi"
|
applicationId = "eu.kanade.tachiyomi"
|
||||||
minSdk = AndroidConfig.minSdk
|
minSdk = AndroidConfig.minSdk
|
||||||
targetSdk = AndroidConfig.targetSdk
|
targetSdk = AndroidConfig.targetSdk
|
||||||
versionCode = 90
|
versionCode = 91
|
||||||
versionName = "0.14.1"
|
versionName = "0.14.2"
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||||
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"")
|
||||||
@ -113,7 +113,6 @@ android {
|
|||||||
"META-INF/README.md",
|
"META-INF/README.md",
|
||||||
"META-INF/NOTICE",
|
"META-INF/NOTICE",
|
||||||
"META-INF/*.kotlin_module",
|
"META-INF/*.kotlin_module",
|
||||||
"META-INF/*.version",
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,8 +175,6 @@ dependencies {
|
|||||||
implementation(compose.accompanist.webview)
|
implementation(compose.accompanist.webview)
|
||||||
implementation(compose.accompanist.swiperefresh)
|
implementation(compose.accompanist.swiperefresh)
|
||||||
implementation(compose.accompanist.flowlayout)
|
implementation(compose.accompanist.flowlayout)
|
||||||
implementation(compose.accompanist.pager.core)
|
|
||||||
implementation(compose.accompanist.pager.indicators)
|
|
||||||
implementation(compose.accompanist.permissions)
|
implementation(compose.accompanist.permissions)
|
||||||
|
|
||||||
implementation(androidx.paging.runtime)
|
implementation(androidx.paging.runtime)
|
||||||
@ -190,6 +187,8 @@ dependencies {
|
|||||||
implementation(libs.sqldelight.android.paging)
|
implementation(libs.sqldelight.android.paging)
|
||||||
|
|
||||||
implementation(kotlinx.reflect)
|
implementation(kotlinx.reflect)
|
||||||
|
|
||||||
|
implementation(platform(kotlinx.coroutines.bom))
|
||||||
implementation(kotlinx.bundles.coroutines)
|
implementation(kotlinx.bundles.coroutines)
|
||||||
|
|
||||||
// AndroidX libraries
|
// AndroidX libraries
|
||||||
@ -298,6 +297,11 @@ androidComponents {
|
|||||||
variantBuilder.enable = variantBuilder.productFlavors.containsAll(listOf("default" to "dev"))
|
variantBuilder.enable = variantBuilder.productFlavors.containsAll(listOf("default" to "dev"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onVariants(selector().withFlavor("default" to "standard")) {
|
||||||
|
// Only excluding in standard flavor because this breaks
|
||||||
|
// Layout Inspector's Compose tree
|
||||||
|
it.packaging.resources.excludes.add("META-INF/*.version")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
@ -34,7 +34,7 @@ import eu.kanade.domain.extension.interactor.GetExtensionSources
|
|||||||
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
||||||
import eu.kanade.domain.history.interactor.DeleteAllHistory
|
import eu.kanade.domain.history.interactor.DeleteAllHistory
|
||||||
import eu.kanade.domain.history.interactor.GetHistory
|
import eu.kanade.domain.history.interactor.GetHistory
|
||||||
import eu.kanade.domain.history.interactor.GetNextChapter
|
import eu.kanade.domain.history.interactor.GetNextUnreadChapters
|
||||||
import eu.kanade.domain.history.interactor.RemoveHistoryById
|
import eu.kanade.domain.history.interactor.RemoveHistoryById
|
||||||
import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId
|
import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId
|
||||||
import eu.kanade.domain.history.interactor.UpsertHistory
|
import eu.kanade.domain.history.interactor.UpsertHistory
|
||||||
@ -94,7 +94,7 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { GetLibraryManga(get()) }
|
addFactory { GetLibraryManga(get()) }
|
||||||
addFactory { GetMangaWithChapters(get(), get()) }
|
addFactory { GetMangaWithChapters(get(), get()) }
|
||||||
addFactory { GetManga(get()) }
|
addFactory { GetManga(get()) }
|
||||||
addFactory { GetNextChapter(get(), get(), get(), get()) }
|
addFactory { GetNextUnreadChapters(get(), get(), get()) }
|
||||||
addFactory { ResetViewerFlags(get()) }
|
addFactory { ResetViewerFlags(get()) }
|
||||||
addFactory { SetMangaChapterFlags(get()) }
|
addFactory { SetMangaChapterFlags(get()) }
|
||||||
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
|
addFactory { SetMangaDefaultChapterFlags(get(), get(), get()) }
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
package eu.kanade.domain.history.interactor
|
|
||||||
|
|
||||||
import eu.kanade.domain.chapter.interactor.GetChapter
|
|
||||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
|
||||||
import eu.kanade.domain.chapter.model.Chapter
|
|
||||||
import eu.kanade.domain.history.repository.HistoryRepository
|
|
||||||
import eu.kanade.domain.manga.interactor.GetManga
|
|
||||||
import eu.kanade.domain.manga.model.Manga
|
|
||||||
import eu.kanade.tachiyomi.util.chapter.getChapterSort
|
|
||||||
|
|
||||||
class GetNextChapter(
|
|
||||||
private val getChapter: GetChapter,
|
|
||||||
private val getChapterByMangaId: GetChapterByMangaId,
|
|
||||||
private val getManga: GetManga,
|
|
||||||
private val historyRepository: HistoryRepository,
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend fun await(): Chapter? {
|
|
||||||
val history = historyRepository.getLastHistory() ?: return null
|
|
||||||
return await(history.mangaId, history.chapterId)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun await(mangaId: Long, chapterId: Long): Chapter? {
|
|
||||||
val chapter = getChapter.await(chapterId) ?: return null
|
|
||||||
val manga = getManga.await(mangaId) ?: return null
|
|
||||||
|
|
||||||
if (!chapter.read) return chapter
|
|
||||||
|
|
||||||
val chapters = getChapterByMangaId.await(mangaId)
|
|
||||||
.sortedWith(getChapterSort(manga, sortDescending = false))
|
|
||||||
|
|
||||||
val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id }
|
|
||||||
return when (manga.sorting) {
|
|
||||||
Manga.CHAPTER_SORTING_SOURCE -> chapters.getOrNull(currChapterIndex + 1)
|
|
||||||
Manga.CHAPTER_SORTING_NUMBER -> {
|
|
||||||
val chapterNumber = chapter.chapterNumber
|
|
||||||
|
|
||||||
((currChapterIndex + 1) until chapters.size)
|
|
||||||
.map { chapters[it] }
|
|
||||||
.firstOrNull {
|
|
||||||
it.chapterNumber > chapterNumber && it.chapterNumber <= chapterNumber + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Manga.CHAPTER_SORTING_UPLOAD_DATE -> {
|
|
||||||
chapters.drop(currChapterIndex + 1)
|
|
||||||
.firstOrNull { it.dateUpload >= chapter.dateUpload }
|
|
||||||
}
|
|
||||||
else -> throw NotImplementedError("Invalid chapter sorting method: ${manga.sorting}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,33 @@
|
|||||||
|
package eu.kanade.domain.history.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
||||||
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
|
import eu.kanade.domain.history.repository.HistoryRepository
|
||||||
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
|
import eu.kanade.tachiyomi.util.chapter.getChapterSort
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
class GetNextUnreadChapters(
|
||||||
|
private val getChapterByMangaId: GetChapterByMangaId,
|
||||||
|
private val getManga: GetManga,
|
||||||
|
private val historyRepository: HistoryRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(): Chapter? {
|
||||||
|
val history = historyRepository.getLastHistory() ?: return null
|
||||||
|
return await(history.mangaId, history.chapterId).firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun await(mangaId: Long): List<Chapter> {
|
||||||
|
val manga = getManga.await(mangaId) ?: return emptyList()
|
||||||
|
return getChapterByMangaId.await(mangaId)
|
||||||
|
.sortedWith(getChapterSort(manga, sortDescending = false))
|
||||||
|
.filterNot { it.read }
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun await(mangaId: Long, fromChapterId: Long): List<Chapter> {
|
||||||
|
val unreadChapters = await(mangaId)
|
||||||
|
val currChapterIndex = unreadChapters.indexOfFirst { it.id == fromChapterId }
|
||||||
|
return unreadChapters.subList(max(0, currChapterIndex), unreadChapters.size)
|
||||||
|
}
|
||||||
|
}
|
@ -7,11 +7,11 @@ class NetworkToLocalManga(
|
|||||||
private val mangaRepository: MangaRepository,
|
private val mangaRepository: MangaRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend fun await(manga: Manga, sourceId: Long): Manga {
|
suspend fun await(manga: Manga): Manga {
|
||||||
val localManga = getManga(manga.url, sourceId)
|
val localManga = getManga(manga.url, manga.source)
|
||||||
return when {
|
return when {
|
||||||
localManga == null -> {
|
localManga == null -> {
|
||||||
val id = insertManga(manga.copy(source = sourceId))
|
val id = insertManga(manga)
|
||||||
manga.copy(id = id!!)
|
manga.copy(id = id!!)
|
||||||
}
|
}
|
||||||
!localManga.favorite -> {
|
!localManga.favorite -> {
|
||||||
|
@ -232,7 +232,7 @@ fun Manga.toMangaUpdate(): MangaUpdate {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SManga.toDomainManga(): Manga {
|
fun SManga.toDomainManga(sourceId: Long): Manga {
|
||||||
return Manga.create().copy(
|
return Manga.create().copy(
|
||||||
url = url,
|
url = url,
|
||||||
title = title,
|
title = title,
|
||||||
@ -244,6 +244,7 @@ fun SManga.toDomainManga(): Manga {
|
|||||||
thumbnailUrl = thumbnail_url,
|
thumbnailUrl = thumbnail_url,
|
||||||
updateStrategy = update_strategy,
|
updateStrategy = update_strategy,
|
||||||
initialized = initialized,
|
initialized = initialized,
|
||||||
|
source = sourceId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,9 @@ import android.content.Intent
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@ -55,9 +52,11 @@ import eu.kanade.presentation.components.DIVIDER_ALPHA
|
|||||||
import eu.kanade.presentation.components.Divider
|
import eu.kanade.presentation.components.Divider
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.PreferenceRow
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||||
|
import eu.kanade.presentation.components.WarningBanner
|
||||||
|
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||||
|
import eu.kanade.presentation.more.settings.widget.TrailingWidgetBuffer
|
||||||
import eu.kanade.presentation.util.horizontalPadding
|
import eu.kanade.presentation.util.horizontalPadding
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
@ -195,23 +194,6 @@ private fun ExtensionDetails(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun WarningBanner(@StringRes textRes: Int) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(MaterialTheme.colorScheme.error)
|
|
||||||
.padding(16.dp),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(textRes),
|
|
||||||
color = MaterialTheme.colorScheme.onError,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DetailsHeader(
|
private fun DetailsHeader(
|
||||||
extension: Extension,
|
extension: Extension,
|
||||||
@ -380,15 +362,14 @@ private fun SourceSwitchPreference(
|
|||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
PreferenceRow(
|
TextPreferenceWidget(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = if (source.labelAsName) {
|
title = if (source.labelAsName) {
|
||||||
source.source.toString()
|
source.source.toString()
|
||||||
} else {
|
} else {
|
||||||
LocaleHelper.getSourceDisplayName(source.source.lang, context)
|
LocaleHelper.getSourceDisplayName(source.source.lang, context)
|
||||||
},
|
},
|
||||||
onClick = { onClickSource(source.source.id) },
|
widget = {
|
||||||
action = {
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
@ -402,9 +383,14 @@ private fun SourceSwitchPreference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Switch(checked = source.enabled, onCheckedChange = null)
|
Switch(
|
||||||
|
checked = source.enabled,
|
||||||
|
onCheckedChange = null,
|
||||||
|
modifier = Modifier.padding(start = TrailingWidgetBuffer),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onPreferenceClick = { onClickSource(source.source.id) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package eu.kanade.presentation.browse
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -11,10 +10,10 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.presentation.components.LazyColumn
|
import eu.kanade.presentation.components.FastScrollLazyColumn
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.PreferenceRow
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
|
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionFilterPresenter
|
import eu.kanade.tachiyomi.ui.browse.extension.ExtensionFilterPresenter
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
@ -42,15 +41,13 @@ fun ExtensionFilterScreen(
|
|||||||
textResource = R.string.empty_screen,
|
textResource = R.string.empty_screen,
|
||||||
modifier = Modifier.padding(contentPadding),
|
modifier = Modifier.padding(contentPadding),
|
||||||
)
|
)
|
||||||
else -> {
|
else -> ExtensionFilterContent(
|
||||||
SourceFilterContent(
|
contentPadding = contentPadding,
|
||||||
contentPadding = contentPadding,
|
state = presenter,
|
||||||
state = presenter,
|
onClickLang = {
|
||||||
onClickLang = {
|
presenter.toggleLanguage(it)
|
||||||
presenter.toggleLanguage(it)
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@ -65,40 +62,24 @@ fun ExtensionFilterScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun SourceFilterContent(
|
private fun ExtensionFilterContent(
|
||||||
contentPadding: PaddingValues,
|
contentPadding: PaddingValues,
|
||||||
state: ExtensionFilterState,
|
state: ExtensionFilterState,
|
||||||
onClickLang: (String) -> Unit,
|
onClickLang: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
FastScrollLazyColumn(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = state.items,
|
items = state.items,
|
||||||
) { model ->
|
) { model ->
|
||||||
ExtensionFilterItem(
|
val lang = model.lang
|
||||||
|
SwitchPreferenceWidget(
|
||||||
modifier = Modifier.animateItemPlacement(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
lang = model.lang,
|
title = LocaleHelper.getSourceDisplayName(lang, LocalContext.current),
|
||||||
enabled = model.enabled,
|
checked = model.enabled,
|
||||||
onClickItem = onClickLang,
|
onCheckedChanged = { onClickLang(lang) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ExtensionFilterItem(
|
|
||||||
modifier: Modifier,
|
|
||||||
lang: String,
|
|
||||||
enabled: Boolean,
|
|
||||||
onClickItem: (String) -> Unit,
|
|
||||||
) {
|
|
||||||
PreferenceRow(
|
|
||||||
modifier = modifier,
|
|
||||||
title = LocaleHelper.getSourceDisplayName(lang, LocalContext.current),
|
|
||||||
action = {
|
|
||||||
Switch(checked = enabled, onCheckedChange = null)
|
|
||||||
},
|
|
||||||
onClick = { onClickItem(lang) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -10,9 +10,9 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
|
import eu.kanade.presentation.components.FastScrollLazyColumn
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
|
||||||
import eu.kanade.presentation.manga.components.BaseMangaListItem
|
import eu.kanade.presentation.manga.components.BaseMangaListItem
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaPresenter
|
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaPresenter
|
||||||
@ -72,7 +72,7 @@ private fun MigrateMangaContent(
|
|||||||
onClickItem: (Manga) -> Unit,
|
onClickItem: (Manga) -> Unit,
|
||||||
onClickCover: (Manga) -> Unit,
|
onClickCover: (Manga) -> Unit,
|
||||||
) {
|
) {
|
||||||
ScrollbarLazyColumn(
|
FastScrollLazyColumn(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
items(state.items) { manga ->
|
items(state.items) { manga ->
|
||||||
|
@ -6,12 +6,10 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import eu.kanade.domain.manga.model.Manga
|
import eu.kanade.domain.manga.model.Manga
|
||||||
import eu.kanade.presentation.browse.components.BrowseSourceSearchToolbar
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.presentation.components.SearchToolbar
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
|
||||||
import eu.kanade.tachiyomi.ui.more.MoreController
|
import eu.kanade.tachiyomi.ui.more.MoreController
|
||||||
@ -38,13 +36,11 @@ fun SourceSearchScreen(
|
|||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
BrowseSourceSearchToolbar(
|
SearchToolbar(
|
||||||
searchQuery = presenter.searchQuery ?: "",
|
searchQuery = presenter.searchQuery ?: "",
|
||||||
onSearchQueryChanged = { presenter.searchQuery = it },
|
onChangeSearchQuery = { presenter.searchQuery = it },
|
||||||
placeholderText = stringResource(R.string.action_search_hint),
|
onClickCloseSearch = navigateUp,
|
||||||
navigateUp = navigateUp,
|
onSearch = { presenter.search(it) },
|
||||||
onResetClick = { presenter.searchQuery = "" },
|
|
||||||
onSearchClick = { presenter.search(it) },
|
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -14,10 +13,10 @@ import eu.kanade.domain.source.model.Source
|
|||||||
import eu.kanade.presentation.browse.components.BaseSourceItem
|
import eu.kanade.presentation.browse.components.BaseSourceItem
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
|
import eu.kanade.presentation.components.FastScrollLazyColumn
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.PreferenceRow
|
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.FilterUiModel
|
import eu.kanade.tachiyomi.ui.browse.source.FilterUiModel
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterPresenter
|
import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterPresenter
|
||||||
@ -76,7 +75,7 @@ private fun SourcesFilterContent(
|
|||||||
onClickLang: (String) -> Unit,
|
onClickLang: (String) -> Unit,
|
||||||
onClickSource: (Source) -> Unit,
|
onClickSource: (Source) -> Unit,
|
||||||
) {
|
) {
|
||||||
ScrollbarLazyColumn(
|
FastScrollLazyColumn(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
@ -95,14 +94,12 @@ private fun SourcesFilterContent(
|
|||||||
},
|
},
|
||||||
) { model ->
|
) { model ->
|
||||||
when (model) {
|
when (model) {
|
||||||
is FilterUiModel.Header -> {
|
is FilterUiModel.Header -> SourcesFilterHeader(
|
||||||
SourcesFilterHeader(
|
modifier = Modifier.animateItemPlacement(),
|
||||||
modifier = Modifier.animateItemPlacement(),
|
language = model.language,
|
||||||
language = model.language,
|
enabled = model.enabled,
|
||||||
enabled = model.enabled,
|
onClickItem = onClickLang,
|
||||||
onClickItem = onClickLang,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
is FilterUiModel.Item -> SourcesFilterItem(
|
is FilterUiModel.Item -> SourcesFilterItem(
|
||||||
modifier = Modifier.animateItemPlacement(),
|
modifier = Modifier.animateItemPlacement(),
|
||||||
source = model.source,
|
source = model.source,
|
||||||
@ -121,13 +118,11 @@ private fun SourcesFilterHeader(
|
|||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
onClickItem: (String) -> Unit,
|
onClickItem: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
PreferenceRow(
|
SwitchPreferenceWidget(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = LocaleHelper.getSourceDisplayName(language, LocalContext.current),
|
title = LocaleHelper.getSourceDisplayName(language, LocalContext.current),
|
||||||
action = {
|
checked = enabled,
|
||||||
Switch(checked = enabled, onCheckedChange = null)
|
onCheckedChanged = { onClickItem(language) },
|
||||||
},
|
|
||||||
onClick = { onClickItem(language) },
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
package eu.kanade.presentation.browse.components
|
package eu.kanade.presentation.browse.components
|
||||||
|
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ViewList
|
import androidx.compose.material.icons.filled.ViewList
|
||||||
import androidx.compose.material.icons.filled.ViewModule
|
import androidx.compose.material.icons.filled.ViewModule
|
||||||
import androidx.compose.material.icons.outlined.Help
|
import androidx.compose.material.icons.outlined.Help
|
||||||
import androidx.compose.material.icons.outlined.Public
|
import androidx.compose.material.icons.outlined.Public
|
||||||
import androidx.compose.material.icons.outlined.Search
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -15,14 +12,12 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
|
||||||
import eu.kanade.domain.library.model.LibraryDisplayMode
|
import eu.kanade.domain.library.model.LibraryDisplayMode
|
||||||
import eu.kanade.presentation.browse.BrowseSourceState
|
import eu.kanade.presentation.browse.BrowseSourceState
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.AppBarActions
|
import eu.kanade.presentation.components.AppBarActions
|
||||||
|
import eu.kanade.presentation.components.AppBarTitle
|
||||||
import eu.kanade.presentation.components.DropdownMenu
|
import eu.kanade.presentation.components.DropdownMenu
|
||||||
import eu.kanade.presentation.components.RadioMenuItem
|
import eu.kanade.presentation.components.RadioMenuItem
|
||||||
import eu.kanade.presentation.components.SearchToolbar
|
import eu.kanade.presentation.components.SearchToolbar
|
||||||
@ -42,59 +37,21 @@ fun BrowseSourceToolbar(
|
|||||||
onSearch: (String) -> Unit,
|
onSearch: (String) -> Unit,
|
||||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||||
) {
|
) {
|
||||||
if (state.searchQuery == null) {
|
// Avoid capturing unstable source in actions lambda
|
||||||
BrowseSourceRegularToolbar(
|
val title = source?.name
|
||||||
title = if (state.isUserQuery) state.currentFilter.query else source?.name.orEmpty(),
|
val isLocalSource = source is LocalSource
|
||||||
isLocalSource = source is LocalSource,
|
|
||||||
displayMode = displayMode,
|
|
||||||
onDisplayModeChange = onDisplayModeChange,
|
|
||||||
navigateUp = navigateUp,
|
|
||||||
onSearchClick = { state.searchQuery = if (state.isUserQuery) state.currentFilter.query else "" },
|
|
||||||
onWebViewClick = onWebViewClick,
|
|
||||||
onHelpClick = onHelpClick,
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
val cancelSearch = { state.searchQuery = null }
|
|
||||||
BrowseSourceSearchToolbar(
|
|
||||||
searchQuery = state.searchQuery!!,
|
|
||||||
onSearchQueryChanged = { state.searchQuery = it },
|
|
||||||
placeholderText = stringResource(R.string.action_search_hint),
|
|
||||||
navigateUp = cancelSearch,
|
|
||||||
onResetClick = { state.searchQuery = "" },
|
|
||||||
onSearchClick = {
|
|
||||||
onSearch(it)
|
|
||||||
cancelSearch()
|
|
||||||
},
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
SearchToolbar(
|
||||||
fun BrowseSourceRegularToolbar(
|
|
||||||
title: String,
|
|
||||||
isLocalSource: Boolean,
|
|
||||||
displayMode: LibraryDisplayMode,
|
|
||||||
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
onSearchClick: () -> Unit,
|
|
||||||
onWebViewClick: () -> Unit,
|
|
||||||
onHelpClick: () -> Unit,
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
|
||||||
) {
|
|
||||||
AppBar(
|
|
||||||
navigateUp = navigateUp,
|
navigateUp = navigateUp,
|
||||||
title = title,
|
titleContent = { AppBarTitle(title) },
|
||||||
|
searchQuery = state.searchQuery,
|
||||||
|
onChangeSearchQuery = { state.searchQuery = it },
|
||||||
|
onSearch = onSearch,
|
||||||
|
onClickCloseSearch = navigateUp,
|
||||||
actions = {
|
actions = {
|
||||||
var selectingDisplayMode by remember { mutableStateOf(false) }
|
var selectingDisplayMode by remember { mutableStateOf(false) }
|
||||||
AppBarActions(
|
AppBarActions(
|
||||||
actions = listOf(
|
actions = listOf(
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(R.string.action_search),
|
|
||||||
icon = Icons.Outlined.Search,
|
|
||||||
onClick = onSearchClick,
|
|
||||||
),
|
|
||||||
AppBar.Action(
|
AppBar.Action(
|
||||||
title = stringResource(R.string.action_display_mode),
|
title = stringResource(R.string.action_display_mode),
|
||||||
icon = if (displayMode == LibraryDisplayMode.List) Icons.Filled.ViewList else Icons.Filled.ViewModule,
|
icon = if (displayMode == LibraryDisplayMode.List) Icons.Filled.ViewList else Icons.Filled.ViewModule,
|
||||||
@ -123,18 +80,21 @@ fun BrowseSourceRegularToolbar(
|
|||||||
text = { Text(text = stringResource(R.string.action_display_comfortable_grid)) },
|
text = { Text(text = stringResource(R.string.action_display_comfortable_grid)) },
|
||||||
isChecked = displayMode == LibraryDisplayMode.ComfortableGrid,
|
isChecked = displayMode == LibraryDisplayMode.ComfortableGrid,
|
||||||
) {
|
) {
|
||||||
|
selectingDisplayMode = false
|
||||||
onDisplayModeChange(LibraryDisplayMode.ComfortableGrid)
|
onDisplayModeChange(LibraryDisplayMode.ComfortableGrid)
|
||||||
}
|
}
|
||||||
RadioMenuItem(
|
RadioMenuItem(
|
||||||
text = { Text(text = stringResource(R.string.action_display_grid)) },
|
text = { Text(text = stringResource(R.string.action_display_grid)) },
|
||||||
isChecked = displayMode == LibraryDisplayMode.CompactGrid,
|
isChecked = displayMode == LibraryDisplayMode.CompactGrid,
|
||||||
) {
|
) {
|
||||||
|
selectingDisplayMode = false
|
||||||
onDisplayModeChange(LibraryDisplayMode.CompactGrid)
|
onDisplayModeChange(LibraryDisplayMode.CompactGrid)
|
||||||
}
|
}
|
||||||
RadioMenuItem(
|
RadioMenuItem(
|
||||||
text = { Text(text = stringResource(R.string.action_display_list)) },
|
text = { Text(text = stringResource(R.string.action_display_list)) },
|
||||||
isChecked = displayMode == LibraryDisplayMode.List,
|
isChecked = displayMode == LibraryDisplayMode.List,
|
||||||
) {
|
) {
|
||||||
|
selectingDisplayMode = false
|
||||||
onDisplayModeChange(LibraryDisplayMode.List)
|
onDisplayModeChange(LibraryDisplayMode.List)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,34 +102,3 @@ fun BrowseSourceRegularToolbar(
|
|||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun BrowseSourceSearchToolbar(
|
|
||||||
searchQuery: String,
|
|
||||||
onSearchQueryChanged: (String) -> Unit,
|
|
||||||
placeholderText: String?,
|
|
||||||
navigateUp: () -> Unit,
|
|
||||||
onResetClick: () -> Unit,
|
|
||||||
onSearchClick: (String) -> Unit,
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
|
||||||
) {
|
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
|
||||||
val focusManager = LocalFocusManager.current
|
|
||||||
|
|
||||||
SearchToolbar(
|
|
||||||
searchQuery = searchQuery,
|
|
||||||
onChangeSearchQuery = onSearchQueryChanged,
|
|
||||||
placeholderText = placeholderText,
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
|
|
||||||
keyboardActions = KeyboardActions(
|
|
||||||
onSearch = {
|
|
||||||
onSearchClick(searchQuery)
|
|
||||||
focusManager.clearFocus()
|
|
||||||
keyboardController?.hide()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
onClickCloseSearch = navigateUp,
|
|
||||||
onClickResetSearch = onResetClick,
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -6,8 +6,10 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
@ -22,7 +24,7 @@ fun CategoryCreateDialog(
|
|||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
onCreate: (String) -> Unit,
|
onCreate: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val (name, onNameChange) = remember { mutableStateOf("") }
|
var name by remember { mutableStateOf("") }
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
@ -48,7 +50,7 @@ fun CategoryCreateDialog(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.focusRequester(focusRequester),
|
.focusRequester(focusRequester),
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = onNameChange,
|
onValueChange = { name = it },
|
||||||
label = {
|
label = {
|
||||||
Text(text = stringResource(R.string.name))
|
Text(text = stringResource(R.string.name))
|
||||||
},
|
},
|
||||||
@ -70,7 +72,7 @@ fun CategoryRenameDialog(
|
|||||||
onRename: (String) -> Unit,
|
onRename: (String) -> Unit,
|
||||||
category: Category,
|
category: Category,
|
||||||
) {
|
) {
|
||||||
val (name, onNameChange) = remember { mutableStateOf(category.name) }
|
var name by remember { mutableStateOf(category.name) }
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
@ -96,7 +98,7 @@ fun CategoryRenameDialog(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.focusRequester(focusRequester),
|
.focusRequester(focusRequester),
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = onNameChange,
|
onValueChange = { name = it },
|
||||||
label = {
|
label = {
|
||||||
Text(text = stringResource(R.string.name))
|
Text(text = stringResource(R.string.name))
|
||||||
},
|
},
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
package eu.kanade.presentation.category.components
|
package eu.kanade.presentation.category.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
||||||
import eu.kanade.presentation.util.isScrolledToEnd
|
import eu.kanade.presentation.util.isScrolledToEnd
|
||||||
@ -23,8 +21,6 @@ fun CategoryFloatingActionButton(
|
|||||||
text = { Text(text = stringResource(R.string.action_add)) },
|
text = { Text(text = stringResource(R.string.action_add)) },
|
||||||
icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = "") },
|
icon = { Icon(imageVector = Icons.Outlined.Add, contentDescription = "") },
|
||||||
onClick = onCreate,
|
onClick = onCreate,
|
||||||
modifier = Modifier
|
|
||||||
.navigationBarsPadding(),
|
|
||||||
expanded = lazyListState.isScrollingUp() || lazyListState.isScrolledToEnd(),
|
expanded = lazyListState.isScrollingUp() || lazyListState.isScrolledToEnd(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package eu.kanade.presentation.components
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.statusBars
|
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
@ -15,6 +12,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
import androidx.compose.material.icons.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.outlined.Close
|
import androidx.compose.material.icons.outlined.Close
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
import androidx.compose.material.icons.outlined.MoreVert
|
||||||
|
import androidx.compose.material.icons.outlined.Search
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@ -28,6 +26,7 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.key
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@ -36,8 +35,11 @@ import androidx.compose.ui.focus.FocusRequester
|
|||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@ -140,7 +142,6 @@ fun AppBar(
|
|||||||
},
|
},
|
||||||
title = titleContent,
|
title = titleContent,
|
||||||
actions = actions,
|
actions = actions,
|
||||||
windowInsets = WindowInsets.statusBars,
|
|
||||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||||
elevation = if (isActionMode) 3.dp else 0.dp,
|
elevation = if (isActionMode) 3.dp else 0.dp,
|
||||||
@ -218,15 +219,22 @@ fun AppBarActions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param searchEnabled Set to false if you don't want to show search action.
|
||||||
|
* @param searchQuery If null, use normal toolbar.
|
||||||
|
* @param placeholderText If null, [R.string.action_search_hint] is used.
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun SearchToolbar(
|
fun SearchToolbar(
|
||||||
searchQuery: String,
|
titleContent: @Composable () -> Unit = {},
|
||||||
onChangeSearchQuery: (String) -> Unit,
|
navigateUp: (() -> Unit)? = null,
|
||||||
|
searchEnabled: Boolean = true,
|
||||||
|
searchQuery: String?,
|
||||||
|
onChangeSearchQuery: (String?) -> Unit,
|
||||||
placeholderText: String? = null,
|
placeholderText: String? = null,
|
||||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
onSearch: (String) -> Unit = {},
|
||||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) },
|
||||||
onClickCloseSearch: () -> Unit,
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
onClickResetSearch: () -> Unit,
|
|
||||||
incognitoMode: Boolean = false,
|
incognitoMode: Boolean = false,
|
||||||
downloadedOnlyMode: Boolean = false,
|
downloadedOnlyMode: Boolean = false,
|
||||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||||
@ -234,9 +242,15 @@ fun SearchToolbar(
|
|||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
) {
|
) {
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
var searchClickCount by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
AppBar(
|
AppBar(
|
||||||
titleContent = {
|
titleContent = {
|
||||||
|
if (searchQuery == null) return@AppBar titleContent()
|
||||||
|
|
||||||
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
|
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = searchQuery,
|
value = searchQuery,
|
||||||
onValueChange = onChangeSearchQuery,
|
onValueChange = onChangeSearchQuery,
|
||||||
@ -248,8 +262,14 @@ fun SearchToolbar(
|
|||||||
fontWeight = FontWeight.Normal,
|
fontWeight = FontWeight.Normal,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
),
|
),
|
||||||
keyboardOptions = keyboardOptions,
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
|
||||||
keyboardActions = keyboardActions,
|
keyboardActions = KeyboardActions(
|
||||||
|
onSearch = {
|
||||||
|
onSearch(searchQuery)
|
||||||
|
focusManager.clearFocus()
|
||||||
|
keyboardController?.hide()
|
||||||
|
},
|
||||||
|
),
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground),
|
cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground),
|
||||||
visualTransformation = visualTransformation,
|
visualTransformation = visualTransformation,
|
||||||
@ -263,7 +283,7 @@ fun SearchToolbar(
|
|||||||
visualTransformation = visualTransformation,
|
visualTransformation = visualTransformation,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
placeholder = {
|
placeholder = {
|
||||||
if (!placeholderText.isNullOrEmpty()) {
|
(placeholderText ?: stringResource(R.string.action_search_hint)).let { placeholderText ->
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.secondaryItemAlpha(),
|
modifier = Modifier.secondaryItemAlpha(),
|
||||||
text = placeholderText,
|
text = placeholderText,
|
||||||
@ -280,22 +300,41 @@ fun SearchToolbar(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
navigationIcon = Icons.Outlined.ArrowBack,
|
navigateUp = if (searchQuery == null) navigateUp else onClickCloseSearch,
|
||||||
navigateUp = onClickCloseSearch,
|
|
||||||
actions = {
|
actions = {
|
||||||
AnimatedVisibility(visible = searchQuery.isNotEmpty()) {
|
key("search") {
|
||||||
IconButton(onClick = onClickResetSearch) {
|
val onClick = {
|
||||||
Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
|
searchClickCount++
|
||||||
|
onChangeSearchQuery("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!searchEnabled) {
|
||||||
|
// Don't show search action
|
||||||
|
} else if (searchQuery == null) {
|
||||||
|
IconButton(onClick) {
|
||||||
|
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
|
||||||
|
}
|
||||||
|
} else if (searchQuery.isNotEmpty()) {
|
||||||
|
IconButton(onClick) {
|
||||||
|
Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key("actions") { actions() }
|
||||||
},
|
},
|
||||||
isActionMode = false,
|
isActionMode = false,
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
downloadedOnlyMode = downloadedOnlyMode,
|
||||||
incognitoMode = incognitoMode,
|
incognitoMode = incognitoMode,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
LaunchedEffect(focusRequester) {
|
LaunchedEffect(searchClickCount) {
|
||||||
focusRequester.requestFocus()
|
if (searchQuery == null) return@LaunchedEffect
|
||||||
|
try {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
} catch (_: Throwable) {
|
||||||
|
// TextField is gone
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.presentation.components
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
@ -13,6 +14,23 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun WarningBanner(
|
||||||
|
@StringRes textRes: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(textRes),
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(MaterialTheme.colorScheme.error)
|
||||||
|
.padding(16.dp),
|
||||||
|
color = MaterialTheme.colorScheme.onError,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppStateBanners(
|
fun AppStateBanners(
|
||||||
downloadedOnlyMode: Boolean,
|
downloadedOnlyMode: Boolean,
|
||||||
|
@ -26,6 +26,8 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.composed
|
import androidx.compose.ui.composed
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.Role
|
import androidx.compose.ui.semantics.Role
|
||||||
@ -43,26 +45,41 @@ enum class ChapterDownloadAction {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChapterDownloadIndicator(
|
fun ChapterDownloadIndicator(
|
||||||
|
enabled: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
downloadStateProvider: () -> Download.State,
|
downloadStateProvider: () -> Download.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
onClick: (ChapterDownloadAction) -> Unit,
|
onClick: (ChapterDownloadAction) -> Unit,
|
||||||
) {
|
) {
|
||||||
when (val downloadState = downloadStateProvider()) {
|
when (val downloadState = downloadStateProvider()) {
|
||||||
Download.State.NOT_DOWNLOADED -> NotDownloadedIndicator(modifier = modifier, onClick = onClick)
|
Download.State.NOT_DOWNLOADED -> NotDownloadedIndicator(
|
||||||
|
enabled = enabled,
|
||||||
|
modifier = modifier,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
Download.State.QUEUE, Download.State.DOWNLOADING -> DownloadingIndicator(
|
Download.State.QUEUE, Download.State.DOWNLOADING -> DownloadingIndicator(
|
||||||
|
enabled = enabled,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
downloadState = downloadState,
|
downloadState = downloadState,
|
||||||
downloadProgressProvider = downloadProgressProvider,
|
downloadProgressProvider = downloadProgressProvider,
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
)
|
)
|
||||||
Download.State.DOWNLOADED -> DownloadedIndicator(modifier = modifier, onClick = onClick)
|
Download.State.DOWNLOADED -> DownloadedIndicator(
|
||||||
Download.State.ERROR -> ErrorIndicator(modifier = modifier, onClick = onClick)
|
enabled = enabled,
|
||||||
|
modifier = modifier,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
|
Download.State.ERROR -> ErrorIndicator(
|
||||||
|
enabled = enabled,
|
||||||
|
modifier = modifier,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NotDownloadedIndicator(
|
private fun NotDownloadedIndicator(
|
||||||
|
enabled: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: (ChapterDownloadAction) -> Unit,
|
onClick: (ChapterDownloadAction) -> Unit,
|
||||||
) {
|
) {
|
||||||
@ -70,6 +87,7 @@ private fun NotDownloadedIndicator(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
.size(IconButtonTokens.StateLayerSize)
|
.size(IconButtonTokens.StateLayerSize)
|
||||||
.commonClickable(
|
.commonClickable(
|
||||||
|
enabled = enabled,
|
||||||
onLongClick = { onClick(ChapterDownloadAction.START_NOW) },
|
onLongClick = { onClick(ChapterDownloadAction.START_NOW) },
|
||||||
onClick = { onClick(ChapterDownloadAction.START) },
|
onClick = { onClick(ChapterDownloadAction.START) },
|
||||||
)
|
)
|
||||||
@ -87,6 +105,7 @@ private fun NotDownloadedIndicator(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DownloadingIndicator(
|
private fun DownloadingIndicator(
|
||||||
|
enabled: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
downloadState: Download.State,
|
downloadState: Download.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
@ -97,6 +116,7 @@ private fun DownloadingIndicator(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
.size(IconButtonTokens.StateLayerSize)
|
.size(IconButtonTokens.StateLayerSize)
|
||||||
.commonClickable(
|
.commonClickable(
|
||||||
|
enabled = enabled,
|
||||||
onLongClick = { onClick(ChapterDownloadAction.CANCEL) },
|
onLongClick = { onClick(ChapterDownloadAction.CANCEL) },
|
||||||
onClick = { isMenuExpanded = true },
|
onClick = { isMenuExpanded = true },
|
||||||
),
|
),
|
||||||
@ -158,6 +178,7 @@ private fun DownloadingIndicator(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DownloadedIndicator(
|
private fun DownloadedIndicator(
|
||||||
|
enabled: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: (ChapterDownloadAction) -> Unit,
|
onClick: (ChapterDownloadAction) -> Unit,
|
||||||
) {
|
) {
|
||||||
@ -166,6 +187,7 @@ private fun DownloadedIndicator(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
.size(IconButtonTokens.StateLayerSize)
|
.size(IconButtonTokens.StateLayerSize)
|
||||||
.commonClickable(
|
.commonClickable(
|
||||||
|
enabled = enabled,
|
||||||
onLongClick = { onClick(ChapterDownloadAction.DELETE) },
|
onLongClick = { onClick(ChapterDownloadAction.DELETE) },
|
||||||
onClick = { isMenuExpanded = true },
|
onClick = { isMenuExpanded = true },
|
||||||
),
|
),
|
||||||
@ -191,6 +213,7 @@ private fun DownloadedIndicator(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ErrorIndicator(
|
private fun ErrorIndicator(
|
||||||
|
enabled: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: (ChapterDownloadAction) -> Unit,
|
onClick: (ChapterDownloadAction) -> Unit,
|
||||||
) {
|
) {
|
||||||
@ -198,6 +221,7 @@ private fun ErrorIndicator(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
.size(IconButtonTokens.StateLayerSize)
|
.size(IconButtonTokens.StateLayerSize)
|
||||||
.commonClickable(
|
.commonClickable(
|
||||||
|
enabled = enabled,
|
||||||
onLongClick = { onClick(ChapterDownloadAction.START) },
|
onLongClick = { onClick(ChapterDownloadAction.START) },
|
||||||
onClick = { onClick(ChapterDownloadAction.START) },
|
onClick = { onClick(ChapterDownloadAction.START) },
|
||||||
),
|
),
|
||||||
@ -213,11 +237,18 @@ private fun ErrorIndicator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Modifier.commonClickable(
|
private fun Modifier.commonClickable(
|
||||||
|
enabled: Boolean,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) = composed {
|
) = composed {
|
||||||
|
val haptic = LocalHapticFeedback.current
|
||||||
|
|
||||||
this.combinedClickable(
|
this.combinedClickable(
|
||||||
onLongClick = onLongClick,
|
enabled = enabled,
|
||||||
|
onLongClick = {
|
||||||
|
onLongClick()
|
||||||
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
},
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
role = Role.Button,
|
role = Role.Button,
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
const val DIVIDER_ALPHA = 0.2f
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Divider(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Divider(
|
||||||
|
modifier = modifier,
|
||||||
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = DIVIDER_ALPHA),
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DownloadDropdownMenu(
|
||||||
|
expanded: Boolean,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
onDownloadClicked: (DownloadAction) -> Unit,
|
||||||
|
includeDownloadAllOption: Boolean = true,
|
||||||
|
) {
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download_1)) },
|
||||||
|
onClick = {
|
||||||
|
onDownloadClicked(DownloadAction.NEXT_1_CHAPTER)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download_5)) },
|
||||||
|
onClick = {
|
||||||
|
onDownloadClicked(DownloadAction.NEXT_5_CHAPTERS)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download_10)) },
|
||||||
|
onClick = {
|
||||||
|
onDownloadClicked(DownloadAction.NEXT_10_CHAPTERS)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download_custom)) },
|
||||||
|
onClick = {
|
||||||
|
onDownloadClicked(DownloadAction.CUSTOM)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download_unread)) },
|
||||||
|
onClick = {
|
||||||
|
onDownloadClicked(DownloadAction.UNREAD_CHAPTERS)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (includeDownloadAllOption) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.download_all)) },
|
||||||
|
onClick = {
|
||||||
|
onDownloadClicked(DownloadAction.ALL_CHAPTERS)
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,29 @@
|
|||||||
package eu.kanade.presentation.components
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
import androidx.compose.foundation.layout.sizeIn
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.MoreVert
|
||||||
import androidx.compose.material.icons.outlined.RadioButtonChecked
|
import androidx.compose.material.icons.outlined.RadioButtonChecked
|
||||||
import androidx.compose.material.icons.outlined.RadioButtonUnchecked
|
import androidx.compose.material.icons.outlined.RadioButtonUnchecked
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.DpOffset
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.PopupProperties
|
import androidx.compose.ui.window.PopupProperties
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import me.saket.cascade.CascadeColumnScope
|
||||||
|
import me.saket.cascade.CascadeDropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenu as ComposeDropdownMenu
|
import androidx.compose.material3.DropdownMenu as ComposeDropdownMenu
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -22,6 +31,7 @@ fun DropdownMenu(
|
|||||||
expanded: Boolean,
|
expanded: Boolean,
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
offset: DpOffset = DpOffset(8.dp, (-56).dp),
|
||||||
properties: PopupProperties = PopupProperties(focusable = true),
|
properties: PopupProperties = PopupProperties(focusable = true),
|
||||||
content: @Composable ColumnScope.() -> Unit,
|
content: @Composable ColumnScope.() -> Unit,
|
||||||
) {
|
) {
|
||||||
@ -29,7 +39,7 @@ fun DropdownMenu(
|
|||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
modifier = modifier.sizeIn(minWidth = 196.dp, maxWidth = 196.dp),
|
modifier = modifier.sizeIn(minWidth = 196.dp, maxWidth = 196.dp),
|
||||||
offset = DpOffset(8.dp, (-56).dp),
|
offset = offset,
|
||||||
properties = properties,
|
properties = properties,
|
||||||
content = content,
|
content = content,
|
||||||
)
|
)
|
||||||
@ -60,3 +70,27 @@ fun RadioMenuItem(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OverflowMenu(
|
||||||
|
content: @Composable CascadeColumnScope.(() -> Unit) -> Unit,
|
||||||
|
) {
|
||||||
|
var moreExpanded by remember { mutableStateOf(false) }
|
||||||
|
val closeMenu = { moreExpanded = false }
|
||||||
|
|
||||||
|
Box {
|
||||||
|
IconButton(onClick = { moreExpanded = !moreExpanded }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.MoreVert,
|
||||||
|
contentDescription = stringResource(R.string.abc_action_menu_overflow_description),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CascadeDropdownMenu(
|
||||||
|
expanded = moreExpanded,
|
||||||
|
onDismissRequest = closeMenu,
|
||||||
|
offset = DpOffset(8.dp, (-56).dp),
|
||||||
|
) {
|
||||||
|
content(closeMenu)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -29,6 +29,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.util.fastFirstOrNull
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import eu.kanade.presentation.util.secondaryItemAlpha
|
import eu.kanade.presentation.util.secondaryItemAlpha
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -100,9 +101,9 @@ fun EmptyScreen(
|
|||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
) { measurables, constraints ->
|
) { measurables, constraints ->
|
||||||
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
|
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
|
||||||
val facePlaceable = measurables.first { it.layoutId == "face" }
|
val facePlaceable = measurables.fastFirstOrNull { it.layoutId == "face" }!!
|
||||||
.measure(looseConstraints)
|
.measure(looseConstraints)
|
||||||
val actionsPlaceable = measurables.firstOrNull { it.layoutId == "actions" }
|
val actionsPlaceable = measurables.fastFirstOrNull { it.layoutId == "actions" }
|
||||||
?.measure(looseConstraints)
|
?.measure(looseConstraints)
|
||||||
|
|
||||||
layout(constraints.maxWidth, constraints.maxHeight) {
|
layout(constraints.maxWidth, constraints.maxHeight) {
|
||||||
|
@ -37,8 +37,10 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
@ -48,6 +50,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -170,6 +173,7 @@ private fun RowScope.Button(
|
|||||||
toConfirm: Boolean,
|
toConfirm: Boolean,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
|
content: (@Composable () -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val animatedWeight by animateFloatAsState(if (toConfirm) 2f else 1f)
|
val animatedWeight by animateFloatAsState(if (toConfirm) 2f else 1f)
|
||||||
Column(
|
Column(
|
||||||
@ -201,6 +205,7 @@ private fun RowScope.Button(
|
|||||||
style = MaterialTheme.typography.labelSmall,
|
style = MaterialTheme.typography.labelSmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
content?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +216,7 @@ fun LibraryBottomActionMenu(
|
|||||||
onChangeCategoryClicked: (() -> Unit)?,
|
onChangeCategoryClicked: (() -> Unit)?,
|
||||||
onMarkAsReadClicked: (() -> Unit)?,
|
onMarkAsReadClicked: (() -> Unit)?,
|
||||||
onMarkAsUnreadClicked: (() -> Unit)?,
|
onMarkAsUnreadClicked: (() -> Unit)?,
|
||||||
onDownloadClicked: (() -> Unit)?,
|
onDownloadClicked: ((DownloadAction) -> Unit)?,
|
||||||
onDeleteClicked: (() -> Unit)?,
|
onDeleteClicked: (() -> Unit)?,
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
@ -270,13 +275,22 @@ fun LibraryBottomActionMenu(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (onDownloadClicked != null) {
|
if (onDownloadClicked != null) {
|
||||||
|
var downloadExpanded by remember { mutableStateOf(false) }
|
||||||
Button(
|
Button(
|
||||||
title = stringResource(R.string.action_download),
|
title = stringResource(R.string.action_download),
|
||||||
icon = Icons.Outlined.Download,
|
icon = Icons.Outlined.Download,
|
||||||
toConfirm = confirm[3],
|
toConfirm = confirm[3],
|
||||||
onLongClick = { onLongClickItem(3) },
|
onLongClick = { onLongClickItem(3) },
|
||||||
onClick = onDownloadClicked,
|
onClick = { downloadExpanded = !downloadExpanded },
|
||||||
)
|
) {
|
||||||
|
val onDismissRequest = { downloadExpanded = false }
|
||||||
|
DownloadDropdownMenu(
|
||||||
|
expanded = downloadExpanded,
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
onDownloadClicked = onDownloadClicked,
|
||||||
|
includeDownloadAllOption = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (onDeleteClicked != null) {
|
if (onDeleteClicked != null) {
|
||||||
Button(
|
Button(
|
||||||
|
182
app/src/main/java/eu/kanade/presentation/components/Pager.kt
Normal file
182
app/src/main/java/eu/kanade/presentation/components/Pager.kt
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.gestures.snapping.rememberSnapFlingBehavior
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.foundation.lazy.LazyListItemInfo
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.saveable.Saver
|
||||||
|
import androidx.compose.runtime.saveable.listSaver
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.util.fastMaxBy
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun HorizontalPager(
|
||||||
|
count: Int,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
state: PagerState = rememberPagerState(),
|
||||||
|
key: ((page: Int) -> Any)? = null,
|
||||||
|
contentPadding: PaddingValues = PaddingValues(),
|
||||||
|
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
|
||||||
|
userScrollEnabled: Boolean = true,
|
||||||
|
content: @Composable BoxScope.(page: Int) -> Unit,
|
||||||
|
) {
|
||||||
|
Pager(
|
||||||
|
count = count,
|
||||||
|
modifier = modifier,
|
||||||
|
state = state,
|
||||||
|
isVertical = false,
|
||||||
|
key = key,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
verticalAlignment = verticalAlignment,
|
||||||
|
userScrollEnabled = userScrollEnabled,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Pager(
|
||||||
|
count: Int,
|
||||||
|
modifier: Modifier,
|
||||||
|
state: PagerState,
|
||||||
|
isVertical: Boolean,
|
||||||
|
key: ((page: Int) -> Any)?,
|
||||||
|
contentPadding: PaddingValues,
|
||||||
|
userScrollEnabled: Boolean,
|
||||||
|
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
|
||||||
|
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
|
||||||
|
content: @Composable BoxScope.(page: Int) -> Unit,
|
||||||
|
) {
|
||||||
|
LaunchedEffect(count) {
|
||||||
|
state.currentPage = minOf(count - 1, state.currentPage).coerceAtLeast(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
snapshotFlow { state.mostVisiblePageLayoutInfo?.index }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collect { state.updateCurrentPageBasedOnLazyListState() }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVertical) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = modifier,
|
||||||
|
state = state.lazyListState,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
horizontalAlignment = horizontalAlignment,
|
||||||
|
verticalArrangement = Arrangement.aligned(verticalAlignment),
|
||||||
|
userScrollEnabled = userScrollEnabled,
|
||||||
|
flingBehavior = rememberSnapFlingBehavior(lazyListState = state.lazyListState),
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
count = count,
|
||||||
|
key = key,
|
||||||
|
) { page ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillParentMaxHeight()
|
||||||
|
.wrapContentSize(),
|
||||||
|
) {
|
||||||
|
content(this, page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyRow(
|
||||||
|
modifier = modifier,
|
||||||
|
state = state.lazyListState,
|
||||||
|
contentPadding = contentPadding,
|
||||||
|
verticalAlignment = verticalAlignment,
|
||||||
|
horizontalArrangement = Arrangement.aligned(horizontalAlignment),
|
||||||
|
userScrollEnabled = userScrollEnabled,
|
||||||
|
flingBehavior = rememberSnapFlingBehavior(lazyListState = state.lazyListState),
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
count = count,
|
||||||
|
key = key,
|
||||||
|
) { page ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillParentMaxWidth()
|
||||||
|
.wrapContentSize(),
|
||||||
|
) {
|
||||||
|
content(this, page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberPagerState(
|
||||||
|
initialPage: Int = 0,
|
||||||
|
) = rememberSaveable(saver = PagerState.Saver) {
|
||||||
|
PagerState(currentPage = initialPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
class PagerState(
|
||||||
|
currentPage: Int = 0,
|
||||||
|
) {
|
||||||
|
init { check(currentPage >= 0) { "currentPage cannot be less than zero" } }
|
||||||
|
|
||||||
|
val lazyListState = LazyListState(firstVisibleItemIndex = currentPage)
|
||||||
|
|
||||||
|
private var _currentPage by mutableStateOf(currentPage)
|
||||||
|
|
||||||
|
var currentPage: Int
|
||||||
|
get() = _currentPage
|
||||||
|
set(value) {
|
||||||
|
if (value != _currentPage) {
|
||||||
|
_currentPage = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val mostVisiblePageLayoutInfo: LazyListItemInfo?
|
||||||
|
get() {
|
||||||
|
val layoutInfo = lazyListState.layoutInfo
|
||||||
|
return layoutInfo.visibleItemsInfo.fastMaxBy {
|
||||||
|
val start = maxOf(it.offset, 0)
|
||||||
|
val end = minOf(
|
||||||
|
it.offset + it.size,
|
||||||
|
layoutInfo.viewportEndOffset - layoutInfo.afterContentPadding,
|
||||||
|
)
|
||||||
|
end - start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateCurrentPageBasedOnLazyListState() {
|
||||||
|
mostVisiblePageLayoutInfo?.let {
|
||||||
|
currentPage = it.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun animateScrollToPage(page: Int) {
|
||||||
|
lazyListState.animateScrollToItem(index = page)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun scrollToPage(page: Int) {
|
||||||
|
lazyListState.scrollToItem(index = page)
|
||||||
|
updateCurrentPageBasedOnLazyListState()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Saver: Saver<PagerState, *> = listSaver(
|
||||||
|
save = { listOf(it.currentPage) },
|
||||||
|
restore = { PagerState(it[0]) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -42,7 +42,6 @@ fun Pill(
|
|||||||
text = text,
|
text = text,
|
||||||
fontSize = fontSize,
|
fontSize = fontSize,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
softWrap = false,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
package eu.kanade.presentation.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.heightIn
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.widthIn
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Switch
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import eu.kanade.core.prefs.PreferenceMutableState
|
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
|
||||||
import eu.kanade.presentation.util.horizontalPadding
|
|
||||||
|
|
||||||
const val DIVIDER_ALPHA = 0.2f
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Divider(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
androidx.compose.material3.Divider(
|
|
||||||
modifier = modifier,
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = DIVIDER_ALPHA),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun PreferenceRow(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
title: String,
|
|
||||||
painter: Painter? = null,
|
|
||||||
onClick: () -> Unit = {},
|
|
||||||
onLongClick: () -> Unit = {},
|
|
||||||
subtitle: String? = null,
|
|
||||||
action: @Composable (() -> Unit)? = null,
|
|
||||||
) {
|
|
||||||
val height = if (subtitle != null) 72.dp else 56.dp
|
|
||||||
|
|
||||||
val titleTextStyle = MaterialTheme.typography.bodyLarge
|
|
||||||
val subtitleTextStyle = MaterialTheme.typography.bodyMedium.copy(
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.75f),
|
|
||||||
)
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.heightIn(min = height)
|
|
||||||
.combinedClickable(
|
|
||||||
onLongClick = onLongClick,
|
|
||||||
onClick = onClick,
|
|
||||||
),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
|
||||||
if (painter != null) {
|
|
||||||
Icon(
|
|
||||||
painter = painter,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = horizontalPadding, end = 16.dp)
|
|
||||||
.size(24.dp),
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(
|
|
||||||
Modifier
|
|
||||||
.padding(horizontal = 16.dp)
|
|
||||||
.weight(1f),
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
style = titleTextStyle,
|
|
||||||
)
|
|
||||||
if (subtitle != null) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(top = 4.dp),
|
|
||||||
text = subtitle,
|
|
||||||
style = subtitleTextStyle,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (action != null) {
|
|
||||||
Box(
|
|
||||||
Modifier
|
|
||||||
.widthIn(min = 56.dp)
|
|
||||||
.padding(end = horizontalPadding),
|
|
||||||
) {
|
|
||||||
action()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SwitchPreference(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
checked: Boolean,
|
|
||||||
onClick: () -> Unit,
|
|
||||||
title: String,
|
|
||||||
subtitle: String? = null,
|
|
||||||
painter: Painter? = null,
|
|
||||||
) {
|
|
||||||
PreferenceRow(
|
|
||||||
modifier = modifier,
|
|
||||||
title = title,
|
|
||||||
subtitle = subtitle,
|
|
||||||
painter = painter,
|
|
||||||
action = { Switch(checked = checked, onCheckedChange = null) },
|
|
||||||
onClick = onClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SwitchPreference(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
preference: PreferenceMutableState<Boolean>,
|
|
||||||
title: String,
|
|
||||||
subtitle: String? = null,
|
|
||||||
painter: Painter? = null,
|
|
||||||
) {
|
|
||||||
SwitchPreference(
|
|
||||||
modifier = modifier,
|
|
||||||
title = title,
|
|
||||||
subtitle = subtitle,
|
|
||||||
painter = painter,
|
|
||||||
checked = preference.value,
|
|
||||||
onClick = { preference.value = !preference.value },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
private fun PreferencesPreview() {
|
|
||||||
TachiyomiTheme {
|
|
||||||
Column {
|
|
||||||
PreferenceRow(
|
|
||||||
title = "Plain",
|
|
||||||
subtitle = "Subtitle",
|
|
||||||
)
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
|
|
||||||
SwitchPreference(
|
|
||||||
title = "Switch (on)",
|
|
||||||
subtitle = "Subtitle",
|
|
||||||
checked = true,
|
|
||||||
onClick = {},
|
|
||||||
)
|
|
||||||
SwitchPreference(
|
|
||||||
title = "Switch (off)",
|
|
||||||
subtitle = "Subtitle",
|
|
||||||
checked = false,
|
|
||||||
onClick = {},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,9 +19,11 @@ package eu.kanade.presentation.components
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
import androidx.compose.foundation.layout.calculateEndPadding
|
||||||
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.ScaffoldDefaults
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.material3.contentColorFor
|
import androidx.compose.material3.contentColorFor
|
||||||
@ -37,6 +39,11 @@ import androidx.compose.ui.layout.SubcomposeLayout
|
|||||||
import androidx.compose.ui.unit.Constraints
|
import androidx.compose.ui.unit.Constraints
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.max
|
||||||
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import androidx.compose.ui.util.fastMap
|
||||||
|
import androidx.compose.ui.util.fastMaxBy
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <a href="https://material.io/design/layout/understanding-layout.html" class="external" target="_blank">Material Design layout</a>.
|
* <a href="https://material.io/design/layout/understanding-layout.html" class="external" target="_blank">Material Design layout</a>.
|
||||||
@ -59,6 +66,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
* * Pass scroll behavior to top bar by default
|
* * Pass scroll behavior to top bar by default
|
||||||
* * Remove height constraint for expanded app bar
|
* * Remove height constraint for expanded app bar
|
||||||
* * Also take account of fab height when providing inner padding
|
* * Also take account of fab height when providing inner padding
|
||||||
|
* * Fixes for fab and snackbar horizontal placements when [contentWindowInsets] is used
|
||||||
*
|
*
|
||||||
* @param modifier the [Modifier] to be applied to this scaffold
|
* @param modifier the [Modifier] to be applied to this scaffold
|
||||||
* @param topBar top app bar of the screen, typically a [SmallTopAppBar]
|
* @param topBar top app bar of the screen, typically a [SmallTopAppBar]
|
||||||
@ -72,6 +80,9 @@ import androidx.compose.ui.unit.dp
|
|||||||
* @param contentColor the preferred color for content inside this scaffold. Defaults to either the
|
* @param contentColor the preferred color for content inside this scaffold. Defaults to either the
|
||||||
* matching content color for [containerColor], or to the current [LocalContentColor] if
|
* matching content color for [containerColor], or to the current [LocalContentColor] if
|
||||||
* [containerColor] is not a color from the theme.
|
* [containerColor] is not a color from the theme.
|
||||||
|
* @param contentWindowInsets window insets to be passed to content slot via PaddingValues params.
|
||||||
|
* Scaffold will take the insets into account from the top/bottom only if the topBar/ bottomBar
|
||||||
|
* are not present, as the scaffold expect topBar/bottomBar to handle insets instead
|
||||||
* @param content content of the screen. The lambda receives a [PaddingValues] that should be
|
* @param content content of the screen. The lambda receives a [PaddingValues] that should be
|
||||||
* applied to the content root via [Modifier.padding] and [Modifier.consumeWindowInsets] to
|
* applied to the content root via [Modifier.padding] and [Modifier.consumeWindowInsets] to
|
||||||
* properly offset top and bottom bars. If using [Modifier.verticalScroll], apply this modifier to
|
* properly offset top and bottom bars. If using [Modifier.verticalScroll], apply this modifier to
|
||||||
@ -89,6 +100,7 @@ fun Scaffold(
|
|||||||
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
floatingActionButtonPosition: FabPosition = FabPosition.End,
|
||||||
containerColor: Color = MaterialTheme.colorScheme.background,
|
containerColor: Color = MaterialTheme.colorScheme.background,
|
||||||
contentColor: Color = contentColorFor(containerColor),
|
contentColor: Color = contentColorFor(containerColor),
|
||||||
|
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
|
||||||
content: @Composable (PaddingValues) -> Unit,
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
) {
|
) {
|
||||||
androidx.compose.material3.Surface(
|
androidx.compose.material3.Surface(
|
||||||
@ -104,6 +116,7 @@ fun Scaffold(
|
|||||||
bottomBar = bottomBar,
|
bottomBar = bottomBar,
|
||||||
content = content,
|
content = content,
|
||||||
snackbar = snackbarHost,
|
snackbar = snackbarHost,
|
||||||
|
contentWindowInsets = contentWindowInsets,
|
||||||
fab = floatingActionButton,
|
fab = floatingActionButton,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -129,6 +142,7 @@ private fun ScaffoldLayout(
|
|||||||
content: @Composable (PaddingValues) -> Unit,
|
content: @Composable (PaddingValues) -> Unit,
|
||||||
snackbar: @Composable () -> Unit,
|
snackbar: @Composable () -> Unit,
|
||||||
fab: @Composable () -> Unit,
|
fab: @Composable () -> Unit,
|
||||||
|
contentWindowInsets: WindowInsets,
|
||||||
bottomBar: @Composable () -> Unit,
|
bottomBar: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
SubcomposeLayout { constraints ->
|
SubcomposeLayout { constraints ->
|
||||||
@ -143,37 +157,51 @@ private fun ScaffoldLayout(
|
|||||||
val topBarConstraints = looseConstraints.copy(maxHeight = Constraints.Infinity)
|
val topBarConstraints = looseConstraints.copy(maxHeight = Constraints.Infinity)
|
||||||
|
|
||||||
layout(layoutWidth, layoutHeight) {
|
layout(layoutWidth, layoutHeight) {
|
||||||
val topBarPlaceables = subcompose(ScaffoldLayoutContent.TopBar, topBar).map {
|
val leftInset = contentWindowInsets.getLeft(this@SubcomposeLayout, layoutDirection)
|
||||||
|
val rightInset = contentWindowInsets.getRight(this@SubcomposeLayout, layoutDirection)
|
||||||
|
val bottomInset = contentWindowInsets.getBottom(this@SubcomposeLayout)
|
||||||
|
// Tachiyomi: layoutWidth after horizontal insets
|
||||||
|
val insetLayoutWidth = layoutWidth - leftInset - rightInset
|
||||||
|
|
||||||
|
val topBarPlaceables = subcompose(ScaffoldLayoutContent.TopBar, topBar).fastMap {
|
||||||
it.measure(topBarConstraints)
|
it.measure(topBarConstraints)
|
||||||
}
|
}
|
||||||
|
|
||||||
val topBarHeight = topBarPlaceables.maxByOrNull { it.height }?.height ?: 0
|
val topBarHeight = topBarPlaceables.fastMaxBy { it.height }?.height ?: 0
|
||||||
|
|
||||||
val snackbarPlaceables = subcompose(ScaffoldLayoutContent.Snackbar, snackbar).map {
|
val snackbarPlaceables = subcompose(ScaffoldLayoutContent.Snackbar, snackbar).fastMap {
|
||||||
it.measure(looseConstraints)
|
it.measure(looseConstraints)
|
||||||
}
|
}
|
||||||
|
|
||||||
val snackbarHeight = snackbarPlaceables.maxByOrNull { it.height }?.height ?: 0
|
val snackbarHeight = snackbarPlaceables.fastMaxBy { it.height }?.height ?: 0
|
||||||
val snackbarWidth = snackbarPlaceables.maxByOrNull { it.width }?.width ?: 0
|
val snackbarWidth = snackbarPlaceables.fastMaxBy { it.width }?.width ?: 0
|
||||||
|
|
||||||
|
// Tachiyomi: Calculate insets for snackbar placement offset
|
||||||
|
val snackbarLeft = if (snackbarPlaceables.isNotEmpty()) {
|
||||||
|
(insetLayoutWidth - snackbarWidth) / 2 + leftInset
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
val fabPlaceables =
|
val fabPlaceables =
|
||||||
subcompose(ScaffoldLayoutContent.Fab, fab).mapNotNull { measurable ->
|
subcompose(ScaffoldLayoutContent.Fab, fab).fastMap { measurable ->
|
||||||
measurable.measure(looseConstraints).takeIf { it.height != 0 && it.width != 0 }
|
measurable.measure(looseConstraints)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fabHeight = fabPlaceables.maxByOrNull { it.height }?.height ?: 0
|
val fabWidth = fabPlaceables.fastMaxBy { it.width }?.width ?: 0
|
||||||
|
val fabHeight = fabPlaceables.fastMaxBy { it.height }?.height ?: 0
|
||||||
|
|
||||||
val fabPlacement = if (fabPlaceables.isNotEmpty()) {
|
val fabPlacement = if (fabPlaceables.isNotEmpty() && fabWidth != 0 && fabHeight != 0) {
|
||||||
val fabWidth = fabPlaceables.maxByOrNull { it.width }!!.width
|
|
||||||
// FAB distance from the left of the layout, taking into account LTR / RTL
|
// FAB distance from the left of the layout, taking into account LTR / RTL
|
||||||
|
// Tachiyomi: Calculate insets for fab placement offset
|
||||||
val fabLeftOffset = if (fabPosition == FabPosition.End) {
|
val fabLeftOffset = if (fabPosition == FabPosition.End) {
|
||||||
if (layoutDirection == LayoutDirection.Ltr) {
|
if (layoutDirection == LayoutDirection.Ltr) {
|
||||||
layoutWidth - FabSpacing.roundToPx() - fabWidth
|
layoutWidth - FabSpacing.roundToPx() - fabWidth - rightInset
|
||||||
} else {
|
} else {
|
||||||
FabSpacing.roundToPx()
|
FabSpacing.roundToPx() + leftInset
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(layoutWidth - fabWidth) / 2
|
leftInset + ((insetLayoutWidth - fabWidth) / 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
FabPlacement(
|
FabPlacement(
|
||||||
@ -190,75 +218,63 @@ private fun ScaffoldLayout(
|
|||||||
LocalFabPlacement provides fabPlacement,
|
LocalFabPlacement provides fabPlacement,
|
||||||
content = bottomBar,
|
content = bottomBar,
|
||||||
)
|
)
|
||||||
}.map { it.measure(looseConstraints) }
|
}.fastMap { it.measure(looseConstraints) }
|
||||||
|
|
||||||
val bottomBarHeight = bottomBarPlaceables.maxByOrNull { it.height }?.height ?: 0
|
val bottomBarHeight = bottomBarPlaceables.fastMaxBy { it.height }?.height
|
||||||
val fabOffsetFromBottom = fabPlacement?.let {
|
val fabOffsetFromBottom = fabPlacement?.let {
|
||||||
if (bottomBarHeight == 0) {
|
max(bottomBarHeight ?: 0, bottomInset) + it.height + FabSpacing.roundToPx()
|
||||||
it.height + FabSpacing.roundToPx()
|
|
||||||
} else {
|
|
||||||
// Total height is the bottom bar height + the FAB height + the padding
|
|
||||||
// between the FAB and bottom bar
|
|
||||||
bottomBarHeight + it.height + FabSpacing.roundToPx()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val snackbarOffsetFromBottom = if (snackbarHeight != 0) {
|
val snackbarOffsetFromBottom = if (snackbarHeight != 0) {
|
||||||
snackbarHeight + (fabOffsetFromBottom ?: bottomBarHeight)
|
snackbarHeight + (fabOffsetFromBottom ?: bottomBarHeight ?: bottomInset)
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tachiyomi: Also take account of fab height when providing inner padding
|
|
||||||
*/
|
|
||||||
val bodyContentPlaceables = subcompose(ScaffoldLayoutContent.MainContent) {
|
val bodyContentPlaceables = subcompose(ScaffoldLayoutContent.MainContent) {
|
||||||
val insets = WindowInsets.Companion.safeDrawing
|
val insets = contentWindowInsets.asPaddingValues(this@SubcomposeLayout)
|
||||||
.asPaddingValues(this@SubcomposeLayout)
|
val fabOffsetDp = fabOffsetFromBottom?.toDp() ?: 0.dp
|
||||||
|
val bottomBarHeightPx = bottomBarHeight ?: 0
|
||||||
val innerPadding = PaddingValues(
|
val innerPadding = PaddingValues(
|
||||||
top =
|
top =
|
||||||
if (topBarHeight == 0) {
|
if (topBarPlaceables.isEmpty()) {
|
||||||
insets.calculateTopPadding()
|
insets.calculateTopPadding()
|
||||||
} else {
|
} else {
|
||||||
topBarHeight.toDp()
|
topBarHeight.toDp()
|
||||||
},
|
},
|
||||||
bottom =
|
bottom = // Tachiyomi: Also take account of fab height when providing inner padding
|
||||||
(
|
if (bottomBarPlaceables.isEmpty() || bottomBarHeightPx == 0) {
|
||||||
if (bottomBarHeight == 0) {
|
max(insets.calculateBottomPadding(), fabOffsetDp)
|
||||||
insets.calculateBottomPadding()
|
} else {
|
||||||
} else {
|
max(bottomBarHeightPx.toDp(), fabOffsetDp)
|
||||||
bottomBarHeight.toDp()
|
},
|
||||||
}
|
start = insets.calculateStartPadding((this@SubcomposeLayout).layoutDirection),
|
||||||
) + fabHeight.toDp(),
|
end = insets.calculateEndPadding((this@SubcomposeLayout).layoutDirection),
|
||||||
start = insets.calculateLeftPadding((this@SubcomposeLayout).layoutDirection),
|
|
||||||
end = insets.calculateRightPadding((this@SubcomposeLayout).layoutDirection),
|
|
||||||
)
|
)
|
||||||
content(innerPadding)
|
content(innerPadding)
|
||||||
}.map { it.measure(looseConstraints) }
|
}.fastMap { it.measure(looseConstraints) }
|
||||||
|
|
||||||
// Placing to control drawing order to match default elevation of each placeable
|
// Placing to control drawing order to match default elevation of each placeable
|
||||||
|
|
||||||
bodyContentPlaceables.forEach {
|
bodyContentPlaceables.fastForEach {
|
||||||
it.place(0, 0)
|
it.place(0, 0)
|
||||||
}
|
}
|
||||||
topBarPlaceables.forEach {
|
topBarPlaceables.fastForEach {
|
||||||
it.place(0, 0)
|
it.place(0, 0)
|
||||||
}
|
}
|
||||||
snackbarPlaceables.forEach {
|
snackbarPlaceables.fastForEach {
|
||||||
it.place(
|
it.place(
|
||||||
(layoutWidth - snackbarWidth) / 2,
|
snackbarLeft,
|
||||||
layoutHeight - snackbarOffsetFromBottom,
|
layoutHeight - snackbarOffsetFromBottom,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// The bottom bar is always at the bottom of the layout
|
// The bottom bar is always at the bottom of the layout
|
||||||
bottomBarPlaceables.forEach {
|
bottomBarPlaceables.fastForEach {
|
||||||
it.place(0, layoutHeight - bottomBarHeight)
|
it.place(0, layoutHeight - (bottomBarHeight ?: 0))
|
||||||
}
|
}
|
||||||
// Explicitly not using placeRelative here as `leftOffset` already accounts for RTL
|
// Explicitly not using placeRelative here as `leftOffset` already accounts for RTL
|
||||||
fabPlacement?.let { placement ->
|
fabPlaceables.fastForEach {
|
||||||
fabPlaceables.forEach {
|
it.place(fabPlacement?.left ?: 0, layoutHeight - (fabOffsetFromBottom ?: 0))
|
||||||
it.place(placement.left, layoutHeight - fabOffsetFromBottom!!)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.calculateEndPadding
|
|||||||
import androidx.compose.foundation.layout.calculateStartPadding
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRow
|
import androidx.compose.material3.TabRow
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -16,8 +17,6 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.google.accompanist.pager.HorizontalPager
|
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@ -27,7 +26,6 @@ fun TabbedScreen(
|
|||||||
tabs: List<TabContent>,
|
tabs: List<TabContent>,
|
||||||
startIndex: Int? = null,
|
startIndex: Int? = null,
|
||||||
searchQuery: String? = null,
|
searchQuery: String? = null,
|
||||||
@StringRes placeholderRes: Int? = null,
|
|
||||||
onChangeSearchQuery: (String?) -> Unit = {},
|
onChangeSearchQuery: (String?) -> Unit = {},
|
||||||
incognitoMode: Boolean,
|
incognitoMode: Boolean,
|
||||||
downloadedOnlyMode: Boolean,
|
downloadedOnlyMode: Boolean,
|
||||||
@ -43,28 +41,16 @@ fun TabbedScreen(
|
|||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
if (searchQuery == null) {
|
val tab = tabs[state.currentPage]
|
||||||
AppBar(
|
val searchEnabled = tab.searchEnabled
|
||||||
title = stringResource(titleRes),
|
|
||||||
actions = {
|
SearchToolbar(
|
||||||
AppBarActions(tabs[state.currentPage].actions)
|
titleContent = { AppBarTitle(stringResource(titleRes)) },
|
||||||
},
|
searchEnabled = searchEnabled,
|
||||||
)
|
searchQuery = if (searchEnabled) searchQuery else null,
|
||||||
} else {
|
onChangeSearchQuery = onChangeSearchQuery,
|
||||||
SearchToolbar(
|
actions = { AppBarActions(tab.actions) },
|
||||||
searchQuery = searchQuery,
|
)
|
||||||
placeholderText = placeholderRes?.let { stringResource(it) },
|
|
||||||
onChangeSearchQuery = {
|
|
||||||
onChangeSearchQuery(it)
|
|
||||||
},
|
|
||||||
onClickCloseSearch = {
|
|
||||||
onChangeSearchQuery(null)
|
|
||||||
},
|
|
||||||
onClickResetSearch = {
|
|
||||||
onChangeSearchQuery("")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
Column(
|
Column(
|
||||||
@ -82,9 +68,8 @@ fun TabbedScreen(
|
|||||||
Tab(
|
Tab(
|
||||||
selected = state.currentPage == index,
|
selected = state.currentPage == index,
|
||||||
onClick = { scope.launch { state.animateScrollToPage(index) } },
|
onClick = { scope.launch { state.animateScrollToPage(index) } },
|
||||||
text = {
|
text = { TabText(text = stringResource(tab.titleRes), badgeCount = tab.badgeNumber) },
|
||||||
TabText(stringResource(tab.titleRes), tab.badgeNumber, state.currentPage == index)
|
unselectedContentColor = MaterialTheme.colorScheme.onSurface,
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,6 +95,7 @@ fun TabbedScreen(
|
|||||||
data class TabContent(
|
data class TabContent(
|
||||||
@StringRes val titleRes: Int,
|
@StringRes val titleRes: Int,
|
||||||
val badgeNumber: Int? = null,
|
val badgeNumber: Int? = null,
|
||||||
|
val searchEnabled: Boolean = false,
|
||||||
val actions: List<AppBar.Action> = emptyList(),
|
val actions: List<AppBar.Action> = emptyList(),
|
||||||
val content: @Composable (contentPadding: PaddingValues) -> Unit,
|
val content: @Composable (contentPadding: PaddingValues) -> Unit,
|
||||||
)
|
)
|
||||||
|
@ -30,17 +30,13 @@ fun TabIndicator(currentTabPosition: TabPosition) {
|
|||||||
fun TabText(
|
fun TabText(
|
||||||
text: String,
|
text: String,
|
||||||
badgeCount: Int? = null,
|
badgeCount: Int? = null,
|
||||||
isCurrentPage: Boolean,
|
|
||||||
) {
|
) {
|
||||||
val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f
|
val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(text = text)
|
||||||
text = text,
|
|
||||||
color = if (isCurrentPage) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground,
|
|
||||||
)
|
|
||||||
if (badgeCount != null) {
|
if (badgeCount != null) {
|
||||||
Pill(
|
Pill(
|
||||||
text = "$badgeCount",
|
text = "$badgeCount",
|
||||||
|
@ -7,10 +7,9 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
|
import eu.kanade.presentation.components.FastScrollLazyColumn
|
||||||
import eu.kanade.presentation.components.RelativeDateHeader
|
import eu.kanade.presentation.components.RelativeDateHeader
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
|
||||||
import eu.kanade.presentation.history.HistoryUiModel
|
import eu.kanade.presentation.history.HistoryUiModel
|
||||||
import eu.kanade.presentation.util.plus
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
@ -27,7 +26,7 @@ fun HistoryContent(
|
|||||||
val relativeTime: Int = remember { preferences.relativeTime().get() }
|
val relativeTime: Int = remember { preferences.relativeTime().get() }
|
||||||
val dateFormat: DateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
|
val dateFormat: DateFormat = remember { UiPreferences.dateFormat(preferences.dateFormat().get()) }
|
||||||
|
|
||||||
ScrollbarLazyColumn(
|
FastScrollLazyColumn(
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
|
@ -1,19 +1,13 @@
|
|||||||
package eu.kanade.presentation.history.components
|
package eu.kanade.presentation.history.components
|
||||||
|
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.DeleteSweep
|
import androidx.compose.material.icons.outlined.DeleteSweep
|
||||||
import androidx.compose.material.icons.outlined.Search
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import eu.kanade.presentation.components.AppBarTitle
|
||||||
import eu.kanade.presentation.components.AppBar
|
|
||||||
import eu.kanade.presentation.components.SearchToolbar
|
import eu.kanade.presentation.components.SearchToolbar
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
|
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
|
||||||
@ -26,54 +20,12 @@ fun HistoryToolbar(
|
|||||||
incognitoMode: Boolean,
|
incognitoMode: Boolean,
|
||||||
downloadedOnlyMode: Boolean,
|
downloadedOnlyMode: Boolean,
|
||||||
) {
|
) {
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
SearchToolbar(
|
||||||
val focusManager = LocalFocusManager.current
|
titleContent = { AppBarTitle(stringResource(R.string.history)) },
|
||||||
|
searchQuery = state.searchQuery,
|
||||||
if (state.searchQuery == null) {
|
onChangeSearchQuery = { state.searchQuery = it },
|
||||||
HistoryRegularToolbar(
|
|
||||||
onClickSearch = { state.searchQuery = "" },
|
|
||||||
onClickDelete = { state.dialog = HistoryPresenter.Dialog.DeleteAll },
|
|
||||||
incognitoMode = incognitoMode,
|
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
SearchToolbar(
|
|
||||||
searchQuery = state.searchQuery!!,
|
|
||||||
onChangeSearchQuery = { state.searchQuery = it },
|
|
||||||
placeholderText = stringResource(R.string.action_search_hint),
|
|
||||||
onClickCloseSearch = { state.searchQuery = null },
|
|
||||||
onClickResetSearch = { state.searchQuery = "" },
|
|
||||||
incognitoMode = incognitoMode,
|
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
|
||||||
keyboardOptions = KeyboardOptions.Default.copy(
|
|
||||||
imeAction = ImeAction.Search,
|
|
||||||
),
|
|
||||||
keyboardActions = KeyboardActions(
|
|
||||||
onSearch = {
|
|
||||||
focusManager.clearFocus()
|
|
||||||
keyboardController?.hide()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun HistoryRegularToolbar(
|
|
||||||
onClickSearch: () -> Unit,
|
|
||||||
onClickDelete: () -> Unit,
|
|
||||||
incognitoMode: Boolean,
|
|
||||||
downloadedOnlyMode: Boolean,
|
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
|
||||||
) {
|
|
||||||
AppBar(
|
|
||||||
title = stringResource(R.string.history),
|
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = onClickSearch) {
|
IconButton(onClick = { state.dialog = HistoryPresenter.Dialog.DeleteAll }) {
|
||||||
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
|
|
||||||
}
|
|
||||||
IconButton(onClick = onClickDelete) {
|
|
||||||
Icon(Icons.Outlined.DeleteSweep, contentDescription = stringResource(R.string.pref_clear_history))
|
Icon(Icons.Outlined.DeleteSweep, contentDescription = stringResource(R.string.pref_clear_history))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -6,7 +6,10 @@ import androidx.compose.material.icons.outlined.HelpOutline
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.compose.ui.util.fastAll
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.domain.library.model.display
|
import eu.kanade.domain.library.model.display
|
||||||
import eu.kanade.domain.manga.model.isLocal
|
import eu.kanade.domain.manga.model.isLocal
|
||||||
@ -17,6 +20,7 @@ import eu.kanade.presentation.components.LoadingScreen
|
|||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.library.components.LibraryContent
|
import eu.kanade.presentation.library.components.LibraryContent
|
||||||
import eu.kanade.presentation.library.components.LibraryToolbar
|
import eu.kanade.presentation.library.components.LibraryToolbar
|
||||||
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
import eu.kanade.tachiyomi.ui.library.LibraryPresenter
|
||||||
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
||||||
@ -29,14 +33,17 @@ fun LibraryScreen(
|
|||||||
onChangeCategoryClicked: () -> Unit,
|
onChangeCategoryClicked: () -> Unit,
|
||||||
onMarkAsReadClicked: () -> Unit,
|
onMarkAsReadClicked: () -> Unit,
|
||||||
onMarkAsUnreadClicked: () -> Unit,
|
onMarkAsUnreadClicked: () -> Unit,
|
||||||
onDownloadClicked: () -> Unit,
|
onDownloadClicked: (DownloadAction) -> Unit,
|
||||||
onDeleteClicked: () -> Unit,
|
onDeleteClicked: () -> Unit,
|
||||||
onClickUnselectAll: () -> Unit,
|
onClickUnselectAll: () -> Unit,
|
||||||
onClickSelectAll: () -> Unit,
|
onClickSelectAll: () -> Unit,
|
||||||
onClickInvertSelection: () -> Unit,
|
onClickInvertSelection: () -> Unit,
|
||||||
onClickFilter: () -> Unit,
|
onClickFilter: () -> Unit,
|
||||||
onClickRefresh: (Category?) -> Boolean,
|
onClickRefresh: (Category?) -> Boolean,
|
||||||
|
onClickOpenRandomManga: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val haptic = LocalHapticFeedback.current
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { scrollBehavior ->
|
topBar = { scrollBehavior ->
|
||||||
val title by presenter.getToolbarTitle()
|
val title by presenter.getToolbarTitle()
|
||||||
@ -51,6 +58,7 @@ fun LibraryScreen(
|
|||||||
onClickInvertSelection = onClickInvertSelection,
|
onClickInvertSelection = onClickInvertSelection,
|
||||||
onClickFilter = onClickFilter,
|
onClickFilter = onClickFilter,
|
||||||
onClickRefresh = { onClickRefresh(null) },
|
onClickRefresh = { onClickRefresh(null) },
|
||||||
|
onClickOpenRandomManga = onClickOpenRandomManga,
|
||||||
scrollBehavior = scrollBehavior.takeIf { !tabVisible }, // For scroll overlay when no tab
|
scrollBehavior = scrollBehavior.takeIf { !tabVisible }, // For scroll overlay when no tab
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -60,7 +68,7 @@ fun LibraryScreen(
|
|||||||
onChangeCategoryClicked = onChangeCategoryClicked,
|
onChangeCategoryClicked = onChangeCategoryClicked,
|
||||||
onMarkAsReadClicked = onMarkAsReadClicked,
|
onMarkAsReadClicked = onMarkAsReadClicked,
|
||||||
onMarkAsUnreadClicked = onMarkAsUnreadClicked,
|
onMarkAsUnreadClicked = onMarkAsUnreadClicked,
|
||||||
onDownloadClicked = onDownloadClicked.takeIf { presenter.selection.none { it.manga.isLocal() } },
|
onDownloadClicked = onDownloadClicked.takeIf { presenter.selection.fastAll { !it.manga.isLocal() } },
|
||||||
onDeleteClicked = onDeleteClicked,
|
onDeleteClicked = onDeleteClicked,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -97,7 +105,10 @@ fun LibraryScreen(
|
|||||||
onChangeCurrentPage = { presenter.activeCategory = it },
|
onChangeCurrentPage = { presenter.activeCategory = it },
|
||||||
onMangaClicked = onMangaClicked,
|
onMangaClicked = onMangaClicked,
|
||||||
onToggleSelection = { presenter.toggleSelection(it) },
|
onToggleSelection = { presenter.toggleSelection(it) },
|
||||||
onToggleRangeSelection = { presenter.toggleRangeSelection(it) },
|
onToggleRangeSelection = {
|
||||||
|
presenter.toggleRangeSelection(it)
|
||||||
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
},
|
||||||
onRefresh = onClickRefresh,
|
onRefresh = onClickRefresh,
|
||||||
onGlobalSearchClicked = onGlobalSearchClicked,
|
onGlobalSearchClicked = onGlobalSearchClicked,
|
||||||
getNumberOfMangaForCategory = { presenter.getMangaCountForCategory(it) },
|
getNumberOfMangaForCategory = { presenter.getMangaCountForCategory(it) },
|
||||||
|
@ -15,12 +15,12 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import com.google.accompanist.pager.rememberPagerState
|
|
||||||
import eu.kanade.core.prefs.PreferenceMutableState
|
import eu.kanade.core.prefs.PreferenceMutableState
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.domain.library.model.LibraryDisplayMode
|
import eu.kanade.domain.library.model.LibraryDisplayMode
|
||||||
import eu.kanade.domain.library.model.LibraryManga
|
import eu.kanade.domain.library.model.LibraryManga
|
||||||
import eu.kanade.presentation.components.SwipeRefresh
|
import eu.kanade.presentation.components.SwipeRefresh
|
||||||
|
import eu.kanade.presentation.components.rememberPagerState
|
||||||
import eu.kanade.presentation.library.LibraryState
|
import eu.kanade.presentation.library.LibraryState
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -68,12 +68,13 @@ fun LibraryContent(
|
|||||||
|
|
||||||
if (isLibraryEmpty.not() && showPageTabs && categories.size > 1) {
|
if (isLibraryEmpty.not() && showPageTabs && categories.size > 1) {
|
||||||
LibraryTabs(
|
LibraryTabs(
|
||||||
state = pagerState,
|
|
||||||
categories = categories,
|
categories = categories,
|
||||||
|
currentPageIndex = pagerState.currentPage,
|
||||||
showMangaCount = showMangaCount,
|
showMangaCount = showMangaCount,
|
||||||
getNumberOfMangaForCategory = getNumberOfMangaForCategory,
|
getNumberOfMangaForCategory = getNumberOfMangaForCategory,
|
||||||
isDownloadOnly = isDownloadOnly,
|
isDownloadOnly = isDownloadOnly,
|
||||||
isIncognitoMode = isIncognitoMode,
|
isIncognitoMode = isIncognitoMode,
|
||||||
|
onTabItemClick = { scope.launch { pagerState.animateScrollToPage(it) } },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.presentation.library.components
|
|||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
@ -39,7 +40,10 @@ fun LibraryList(
|
|||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
if (searchQuery.isNullOrEmpty().not()) {
|
if (searchQuery.isNullOrEmpty().not()) {
|
||||||
TextButton(onClick = onGlobalSearchClicked) {
|
TextButton(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
onClick = onGlobalSearchClicked,
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.action_global_search_query, searchQuery!!),
|
text = stringResource(R.string.action_global_search_query, searchQuery!!),
|
||||||
modifier = Modifier.zIndex(99f),
|
modifier = Modifier.zIndex(99f),
|
||||||
|
@ -10,11 +10,11 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import com.google.accompanist.pager.HorizontalPager
|
|
||||||
import com.google.accompanist.pager.PagerState
|
|
||||||
import eu.kanade.core.prefs.PreferenceMutableState
|
import eu.kanade.core.prefs.PreferenceMutableState
|
||||||
import eu.kanade.domain.library.model.LibraryDisplayMode
|
import eu.kanade.domain.library.model.LibraryDisplayMode
|
||||||
import eu.kanade.domain.library.model.LibraryManga
|
import eu.kanade.domain.library.model.LibraryManga
|
||||||
|
import eu.kanade.presentation.components.HorizontalPager
|
||||||
|
import eu.kanade.presentation.components.PagerState
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
import eu.kanade.tachiyomi.ui.library.LibraryItem
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -1,56 +1,54 @@
|
|||||||
package eu.kanade.presentation.library.components
|
package eu.kanade.presentation.library.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ScrollableTabRow
|
import androidx.compose.material3.ScrollableTabRow
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.google.accompanist.pager.PagerState
|
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.presentation.category.visualName
|
import eu.kanade.presentation.category.visualName
|
||||||
import eu.kanade.presentation.components.AppStateBanners
|
import eu.kanade.presentation.components.AppStateBanners
|
||||||
import eu.kanade.presentation.components.Divider
|
import eu.kanade.presentation.components.Divider
|
||||||
import eu.kanade.presentation.components.TabIndicator
|
import eu.kanade.presentation.components.TabIndicator
|
||||||
import eu.kanade.presentation.components.TabText
|
import eu.kanade.presentation.components.TabText
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibraryTabs(
|
fun LibraryTabs(
|
||||||
state: PagerState,
|
|
||||||
categories: List<Category>,
|
categories: List<Category>,
|
||||||
|
currentPageIndex: Int,
|
||||||
showMangaCount: Boolean,
|
showMangaCount: Boolean,
|
||||||
isDownloadOnly: Boolean,
|
isDownloadOnly: Boolean,
|
||||||
isIncognitoMode: Boolean,
|
isIncognitoMode: Boolean,
|
||||||
getNumberOfMangaForCategory: @Composable (Long) -> State<Int?>,
|
getNumberOfMangaForCategory: @Composable (Long) -> State<Int?>,
|
||||||
|
onTabItemClick: (Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
ScrollableTabRow(
|
ScrollableTabRow(
|
||||||
selectedTabIndex = state.currentPage,
|
selectedTabIndex = currentPageIndex,
|
||||||
edgePadding = 0.dp,
|
edgePadding = 0.dp,
|
||||||
indicator = { TabIndicator(it[state.currentPage]) },
|
indicator = { TabIndicator(it[currentPageIndex]) },
|
||||||
// TODO: use default when width is fixed upstream
|
// TODO: use default when width is fixed upstream
|
||||||
// https://issuetracker.google.com/issues/242879624
|
// https://issuetracker.google.com/issues/242879624
|
||||||
divider = {},
|
divider = {},
|
||||||
) {
|
) {
|
||||||
categories.forEachIndexed { index, category ->
|
categories.forEachIndexed { index, category ->
|
||||||
val count by if (showMangaCount) {
|
|
||||||
getNumberOfMangaForCategory(category.id)
|
|
||||||
} else {
|
|
||||||
remember { mutableStateOf<Int?>(null) }
|
|
||||||
}
|
|
||||||
Tab(
|
Tab(
|
||||||
selected = state.currentPage == index,
|
selected = currentPageIndex == index,
|
||||||
onClick = { scope.launch { state.animateScrollToPage(index) } },
|
onClick = { onTabItemClick(index) },
|
||||||
text = {
|
text = {
|
||||||
TabText(category.visualName, count, state.currentPage == index)
|
TabText(
|
||||||
|
text = category.visualName,
|
||||||
|
badgeCount = if (showMangaCount) {
|
||||||
|
getNumberOfMangaForCategory(category.id)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}?.value,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
unselectedContentColor = MaterialTheme.colorScheme.onSurface,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,11 @@ package eu.kanade.presentation.library.components
|
|||||||
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.FilterList
|
import androidx.compose.material.icons.outlined.FilterList
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
import androidx.compose.material.icons.outlined.FlipToBack
|
||||||
import androidx.compose.material.icons.outlined.Refresh
|
|
||||||
import androidx.compose.material.icons.outlined.Search
|
|
||||||
import androidx.compose.material.icons.outlined.SelectAll
|
import androidx.compose.material.icons.outlined.SelectAll
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
@ -19,13 +16,11 @@ import androidx.compose.material3.TopAppBarScrollBehavior
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
|
import eu.kanade.presentation.components.OverflowMenu
|
||||||
import eu.kanade.presentation.components.Pill
|
import eu.kanade.presentation.components.Pill
|
||||||
import eu.kanade.presentation.components.SearchToolbar
|
import eu.kanade.presentation.components.SearchToolbar
|
||||||
import eu.kanade.presentation.library.LibraryState
|
import eu.kanade.presentation.library.LibraryState
|
||||||
@ -43,6 +38,7 @@ fun LibraryToolbar(
|
|||||||
onClickInvertSelection: () -> Unit,
|
onClickInvertSelection: () -> Unit,
|
||||||
onClickFilter: () -> Unit,
|
onClickFilter: () -> Unit,
|
||||||
onClickRefresh: () -> Unit,
|
onClickRefresh: () -> Unit,
|
||||||
|
onClickOpenRandomManga: () -> Unit,
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
scrollBehavior: TopAppBarScrollBehavior?,
|
||||||
) = when {
|
) = when {
|
||||||
state.selectionMode -> LibrarySelectionToolbar(
|
state.selectionMode -> LibrarySelectionToolbar(
|
||||||
@ -53,38 +49,16 @@ fun LibraryToolbar(
|
|||||||
onClickSelectAll = onClickSelectAll,
|
onClickSelectAll = onClickSelectAll,
|
||||||
onClickInvertSelection = onClickInvertSelection,
|
onClickInvertSelection = onClickInvertSelection,
|
||||||
)
|
)
|
||||||
state.searchQuery != null -> {
|
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
|
||||||
val focusManager = LocalFocusManager.current
|
|
||||||
|
|
||||||
SearchToolbar(
|
|
||||||
searchQuery = state.searchQuery!!,
|
|
||||||
onChangeSearchQuery = { state.searchQuery = it },
|
|
||||||
onClickCloseSearch = { state.searchQuery = null },
|
|
||||||
onClickResetSearch = { state.searchQuery = "" },
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
incognitoMode = incognitoMode,
|
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
|
||||||
placeholderText = stringResource(R.string.action_search_hint),
|
|
||||||
keyboardOptions = KeyboardOptions.Default.copy(
|
|
||||||
imeAction = ImeAction.Search,
|
|
||||||
),
|
|
||||||
keyboardActions = KeyboardActions(
|
|
||||||
onSearch = {
|
|
||||||
focusManager.clearFocus()
|
|
||||||
keyboardController?.hide()
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> LibraryRegularToolbar(
|
else -> LibraryRegularToolbar(
|
||||||
title = title,
|
title = title,
|
||||||
hasFilters = state.hasActiveFilters,
|
hasFilters = state.hasActiveFilters,
|
||||||
incognitoMode = incognitoMode,
|
incognitoMode = incognitoMode,
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
downloadedOnlyMode = downloadedOnlyMode,
|
||||||
onClickSearch = { state.searchQuery = "" },
|
searchQuery = state.searchQuery,
|
||||||
|
onChangeSearchQuery = { state.searchQuery = it },
|
||||||
onClickFilter = onClickFilter,
|
onClickFilter = onClickFilter,
|
||||||
onClickRefresh = onClickRefresh,
|
onClickRefresh = onClickRefresh,
|
||||||
|
onClickOpenRandomManga = onClickOpenRandomManga,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -95,14 +69,15 @@ fun LibraryRegularToolbar(
|
|||||||
hasFilters: Boolean,
|
hasFilters: Boolean,
|
||||||
incognitoMode: Boolean,
|
incognitoMode: Boolean,
|
||||||
downloadedOnlyMode: Boolean,
|
downloadedOnlyMode: Boolean,
|
||||||
onClickSearch: () -> Unit,
|
searchQuery: String?,
|
||||||
|
onChangeSearchQuery: (String?) -> Unit,
|
||||||
onClickFilter: () -> Unit,
|
onClickFilter: () -> Unit,
|
||||||
onClickRefresh: () -> Unit,
|
onClickRefresh: () -> Unit,
|
||||||
|
onClickOpenRandomManga: () -> Unit,
|
||||||
scrollBehavior: TopAppBarScrollBehavior?,
|
scrollBehavior: TopAppBarScrollBehavior?,
|
||||||
) {
|
) {
|
||||||
val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f
|
val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f
|
||||||
val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current
|
SearchToolbar(
|
||||||
AppBar(
|
|
||||||
titleContent = {
|
titleContent = {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Text(
|
Text(
|
||||||
@ -120,15 +95,29 @@ fun LibraryRegularToolbar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
searchQuery = searchQuery,
|
||||||
|
onChangeSearchQuery = onChangeSearchQuery,
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = onClickSearch) {
|
val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current
|
||||||
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
|
|
||||||
}
|
|
||||||
IconButton(onClick = onClickFilter) {
|
IconButton(onClick = onClickFilter) {
|
||||||
Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint)
|
Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint)
|
||||||
}
|
}
|
||||||
IconButton(onClick = onClickRefresh) {
|
|
||||||
Icon(Icons.Outlined.Refresh, contentDescription = stringResource(R.string.pref_category_library_update))
|
OverflowMenu { closeMenu ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.pref_category_library_update)) },
|
||||||
|
onClick = {
|
||||||
|
onClickRefresh()
|
||||||
|
closeMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.action_open_random_manga)) },
|
||||||
|
onClick = {
|
||||||
|
onClickOpenRandomManga()
|
||||||
|
closeMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
incognitoMode = incognitoMode,
|
incognitoMode = incognitoMode,
|
||||||
|
@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.calculateEndPadding
|
|||||||
import androidx.compose.foundation.layout.calculateStartPadding
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
|
||||||
import androidx.compose.foundation.layout.only
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
@ -35,6 +34,7 @@ import androidx.compose.runtime.derivedStateOf
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
@ -43,6 +43,9 @@ import androidx.compose.ui.platform.LocalDensity
|
|||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.util.fastAll
|
||||||
|
import androidx.compose.ui.util.fastAny
|
||||||
|
import androidx.compose.ui.util.fastMap
|
||||||
import eu.kanade.domain.chapter.model.Chapter
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
import eu.kanade.presentation.components.ChapterDownloadAction
|
import eu.kanade.presentation.components.ChapterDownloadAction
|
||||||
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
||||||
@ -204,7 +207,7 @@ private fun MangaScreenSmallImpl(
|
|||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters.toList() }
|
||||||
|
|
||||||
val internalOnBackPressed = {
|
val internalOnBackPressed = {
|
||||||
if (chapters.any { it.selected }) {
|
if (chapters.fastAny { it.selected }) {
|
||||||
onAllChapterSelected(false)
|
onAllChapterSelected(false)
|
||||||
} else {
|
} else {
|
||||||
onBackClicked()
|
onBackClicked()
|
||||||
@ -213,8 +216,6 @@ private fun MangaScreenSmallImpl(
|
|||||||
BackHandler(onBack = internalOnBackPressed)
|
BackHandler(onBack = internalOnBackPressed)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier
|
|
||||||
.padding(WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal).asPaddingValues()),
|
|
||||||
topBar = {
|
topBar = {
|
||||||
val firstVisibleItemIndex by remember {
|
val firstVisibleItemIndex by remember {
|
||||||
derivedStateOf { chapterListState.firstVisibleItemIndex }
|
derivedStateOf { chapterListState.firstVisibleItemIndex }
|
||||||
@ -260,13 +261,13 @@ private fun MangaScreenSmallImpl(
|
|||||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = chapters.any { !it.chapter.read } && chapters.none { it.selected },
|
visible = chapters.fastAny { !it.chapter.read } && chapters.fastAll { !it.selected },
|
||||||
enter = fadeIn(),
|
enter = fadeIn(),
|
||||||
exit = fadeOut(),
|
exit = fadeOut(),
|
||||||
) {
|
) {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = {
|
text = {
|
||||||
val id = if (chapters.any { it.chapter.read }) {
|
val id = if (chapters.fastAny { it.chapter.read }) {
|
||||||
R.string.action_resume
|
R.string.action_resume
|
||||||
} else {
|
} else {
|
||||||
R.string.action_start
|
R.string.action_start
|
||||||
@ -276,8 +277,6 @@ private fun MangaScreenSmallImpl(
|
|||||||
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
||||||
onClick = onContinueReading,
|
onClick = onContinueReading,
|
||||||
expanded = chapterListState.isScrollingUp() || chapterListState.isScrolledToEnd(),
|
expanded = chapterListState.isScrollingUp() || chapterListState.isScrolledToEnd(),
|
||||||
modifier = Modifier
|
|
||||||
.padding(WindowInsets.navigationBars.only(WindowInsetsSides.Bottom).asPaddingValues()),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -287,17 +286,21 @@ private fun MangaScreenSmallImpl(
|
|||||||
SwipeRefresh(
|
SwipeRefresh(
|
||||||
refreshing = state.isRefreshingData,
|
refreshing = state.isRefreshingData,
|
||||||
onRefresh = onRefresh,
|
onRefresh = onRefresh,
|
||||||
enabled = chapters.none { it.selected },
|
enabled = chapters.fastAll { !it.selected },
|
||||||
indicatorPadding = contentPadding,
|
indicatorPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
VerticalFastScroller(
|
VerticalFastScroller(
|
||||||
listState = chapterListState,
|
listState = chapterListState,
|
||||||
topContentPadding = topPadding,
|
topContentPadding = topPadding,
|
||||||
|
endContentPadding = contentPadding.calculateEndPadding(layoutDirection),
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxHeight(),
|
modifier = Modifier.fillMaxHeight(),
|
||||||
state = chapterListState,
|
state = chapterListState,
|
||||||
contentPadding = PaddingValues(
|
contentPadding = PaddingValues(
|
||||||
|
start = contentPadding.calculateStartPadding(layoutDirection),
|
||||||
|
end = contentPadding.calculateEndPadding(layoutDirection),
|
||||||
bottom = contentPadding.calculateBottomPadding(),
|
bottom = contentPadding.calculateBottomPadding(),
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
@ -351,6 +354,7 @@ private fun MangaScreenSmallImpl(
|
|||||||
contentType = MangaScreenItem.CHAPTER_HEADER,
|
contentType = MangaScreenItem.CHAPTER_HEADER,
|
||||||
) {
|
) {
|
||||||
ChapterHeader(
|
ChapterHeader(
|
||||||
|
enabled = chapters.fastAll { !it.selected },
|
||||||
chapterCount = chapters.size,
|
chapterCount = chapters.size,
|
||||||
onClick = onFilterClicked,
|
onClick = onFilterClicked,
|
||||||
)
|
)
|
||||||
@ -410,11 +414,11 @@ fun MangaScreenLargeImpl(
|
|||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters.toList() }
|
||||||
|
|
||||||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||||
val (topBarHeight, onTopBarHeightChanged) = remember { mutableStateOf(0) }
|
var topBarHeight by remember { mutableStateOf(0) }
|
||||||
SwipeRefresh(
|
SwipeRefresh(
|
||||||
refreshing = state.isRefreshingData,
|
refreshing = state.isRefreshingData,
|
||||||
onRefresh = onRefresh,
|
onRefresh = onRefresh,
|
||||||
enabled = chapters.none { it.selected },
|
enabled = chapters.fastAll { !it.selected },
|
||||||
indicatorPadding = PaddingValues(
|
indicatorPadding = PaddingValues(
|
||||||
start = insetPadding.calculateStartPadding(layoutDirection),
|
start = insetPadding.calculateStartPadding(layoutDirection),
|
||||||
top = with(density) { topBarHeight.toDp() },
|
top = with(density) { topBarHeight.toDp() },
|
||||||
@ -424,7 +428,7 @@ fun MangaScreenLargeImpl(
|
|||||||
val chapterListState = rememberLazyListState()
|
val chapterListState = rememberLazyListState()
|
||||||
|
|
||||||
val internalOnBackPressed = {
|
val internalOnBackPressed = {
|
||||||
if (chapters.any { it.selected }) {
|
if (chapters.fastAny { it.selected }) {
|
||||||
onAllChapterSelected(false)
|
onAllChapterSelected(false)
|
||||||
} else {
|
} else {
|
||||||
onBackClicked()
|
onBackClicked()
|
||||||
@ -433,12 +437,11 @@ fun MangaScreenLargeImpl(
|
|||||||
BackHandler(onBack = internalOnBackPressed)
|
BackHandler(onBack = internalOnBackPressed)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.padding(insetPadding),
|
|
||||||
topBar = {
|
topBar = {
|
||||||
MangaToolbar(
|
MangaToolbar(
|
||||||
modifier = Modifier.onSizeChanged { onTopBarHeightChanged(it.height) },
|
modifier = Modifier.onSizeChanged { topBarHeight = it.height },
|
||||||
title = state.manga.title,
|
title = state.manga.title,
|
||||||
titleAlphaProvider = { if (chapters.any { it.selected }) 1f else 0f },
|
titleAlphaProvider = { if (chapters.fastAny { it.selected }) 1f else 0f },
|
||||||
backgroundAlphaProvider = { 1f },
|
backgroundAlphaProvider = { 1f },
|
||||||
hasFilters = state.manga.chaptersFiltered(),
|
hasFilters = state.manga.chaptersFiltered(),
|
||||||
incognitoMode = state.isIncognitoMode,
|
incognitoMode = state.isIncognitoMode,
|
||||||
@ -473,13 +476,13 @@ fun MangaScreenLargeImpl(
|
|||||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = chapters.any { !it.chapter.read } && chapters.none { it.selected },
|
visible = chapters.fastAny { !it.chapter.read } && chapters.fastAll { !it.selected },
|
||||||
enter = fadeIn(),
|
enter = fadeIn(),
|
||||||
exit = fadeOut(),
|
exit = fadeOut(),
|
||||||
) {
|
) {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = {
|
text = {
|
||||||
val id = if (chapters.any { it.chapter.read }) {
|
val id = if (chapters.fastAny { it.chapter.read }) {
|
||||||
R.string.action_resume
|
R.string.action_resume
|
||||||
} else {
|
} else {
|
||||||
R.string.action_start
|
R.string.action_start
|
||||||
@ -489,17 +492,20 @@ fun MangaScreenLargeImpl(
|
|||||||
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
icon = { Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null) },
|
||||||
onClick = onContinueReading,
|
onClick = onContinueReading,
|
||||||
expanded = chapterListState.isScrollingUp() || chapterListState.isScrolledToEnd(),
|
expanded = chapterListState.isScrollingUp() || chapterListState.isScrolledToEnd(),
|
||||||
modifier = Modifier
|
|
||||||
.padding(WindowInsets.navigationBars.only(WindowInsetsSides.Bottom).asPaddingValues()),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
) { contentPadding ->
|
) { contentPadding ->
|
||||||
TwoPanelBox(
|
TwoPanelBox(
|
||||||
|
modifier = Modifier.padding(
|
||||||
|
start = contentPadding.calculateStartPadding(layoutDirection),
|
||||||
|
end = contentPadding.calculateEndPadding(layoutDirection),
|
||||||
|
),
|
||||||
startContent = {
|
startContent = {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.verticalScroll(rememberScrollState()),
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(bottom = contentPadding.calculateBottomPadding()),
|
||||||
) {
|
) {
|
||||||
MangaInfoBox(
|
MangaInfoBox(
|
||||||
isTabletUi = true,
|
isTabletUi = true,
|
||||||
@ -548,6 +554,7 @@ fun MangaScreenLargeImpl(
|
|||||||
contentType = MangaScreenItem.CHAPTER_HEADER,
|
contentType = MangaScreenItem.CHAPTER_HEADER,
|
||||||
) {
|
) {
|
||||||
ChapterHeader(
|
ChapterHeader(
|
||||||
|
enabled = chapters.fastAll { !it.selected },
|
||||||
chapterCount = chapters.size,
|
chapterCount = chapters.size,
|
||||||
onClick = onFilterButtonClicked,
|
onClick = onFilterButtonClicked,
|
||||||
)
|
)
|
||||||
@ -582,29 +589,29 @@ private fun SharedMangaBottomActionMenu(
|
|||||||
visible = selected.isNotEmpty(),
|
visible = selected.isNotEmpty(),
|
||||||
modifier = modifier.fillMaxWidth(fillFraction),
|
modifier = modifier.fillMaxWidth(fillFraction),
|
||||||
onBookmarkClicked = {
|
onBookmarkClicked = {
|
||||||
onMultiBookmarkClicked.invoke(selected.map { it.chapter }, true)
|
onMultiBookmarkClicked.invoke(selected.fastMap { it.chapter }, true)
|
||||||
}.takeIf { selected.any { !it.chapter.bookmark } },
|
}.takeIf { selected.fastAny { !it.chapter.bookmark } },
|
||||||
onRemoveBookmarkClicked = {
|
onRemoveBookmarkClicked = {
|
||||||
onMultiBookmarkClicked.invoke(selected.map { it.chapter }, false)
|
onMultiBookmarkClicked.invoke(selected.fastMap { it.chapter }, false)
|
||||||
}.takeIf { selected.all { it.chapter.bookmark } },
|
}.takeIf { selected.fastAll { it.chapter.bookmark } },
|
||||||
onMarkAsReadClicked = {
|
onMarkAsReadClicked = {
|
||||||
onMultiMarkAsReadClicked(selected.map { it.chapter }, true)
|
onMultiMarkAsReadClicked(selected.fastMap { it.chapter }, true)
|
||||||
}.takeIf { selected.any { !it.chapter.read } },
|
}.takeIf { selected.fastAny { !it.chapter.read } },
|
||||||
onMarkAsUnreadClicked = {
|
onMarkAsUnreadClicked = {
|
||||||
onMultiMarkAsReadClicked(selected.map { it.chapter }, false)
|
onMultiMarkAsReadClicked(selected.fastMap { it.chapter }, false)
|
||||||
}.takeIf { selected.any { it.chapter.read || it.chapter.lastPageRead > 0L } },
|
}.takeIf { selected.fastAny { it.chapter.read || it.chapter.lastPageRead > 0L } },
|
||||||
onMarkPreviousAsReadClicked = {
|
onMarkPreviousAsReadClicked = {
|
||||||
onMarkPreviousAsReadClicked(selected[0].chapter)
|
onMarkPreviousAsReadClicked(selected[0].chapter)
|
||||||
}.takeIf { selected.size == 1 },
|
}.takeIf { selected.size == 1 },
|
||||||
onDownloadClicked = {
|
onDownloadClicked = {
|
||||||
onDownloadChapter!!(selected.toList(), ChapterDownloadAction.START)
|
onDownloadChapter!!(selected.toList(), ChapterDownloadAction.START)
|
||||||
}.takeIf {
|
}.takeIf {
|
||||||
onDownloadChapter != null && selected.any { it.downloadState != Download.State.DOWNLOADED }
|
onDownloadChapter != null && selected.fastAny { it.downloadState != Download.State.DOWNLOADED }
|
||||||
},
|
},
|
||||||
onDeleteClicked = {
|
onDeleteClicked = {
|
||||||
onMultiDeleteClicked(selected.map { it.chapter })
|
onMultiDeleteClicked(selected.fastMap { it.chapter })
|
||||||
}.takeIf {
|
}.takeIf {
|
||||||
onDownloadChapter != null && selected.any { it.downloadState == Download.State.DOWNLOADED }
|
onDownloadChapter != null && selected.fastAny { it.downloadState == Download.State.DOWNLOADED }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -629,6 +636,7 @@ private fun LazyListScope.sharedChapterItems(
|
|||||||
read = chapterItem.chapter.read,
|
read = chapterItem.chapter.read,
|
||||||
bookmark = chapterItem.chapter.bookmark,
|
bookmark = chapterItem.chapter.bookmark,
|
||||||
selected = chapterItem.selected,
|
selected = chapterItem.selected,
|
||||||
|
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
|
||||||
downloadStateProvider = { chapterItem.downloadState },
|
downloadStateProvider = { chapterItem.downloadState },
|
||||||
downloadProgressProvider = { chapterItem.downloadProgress },
|
downloadProgressProvider = { chapterItem.downloadProgress },
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
@ -660,7 +668,7 @@ private fun onChapterItemClick(
|
|||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
chapterItem.selected -> onToggleSelection(false)
|
chapterItem.selected -> onToggleSelection(false)
|
||||||
chapters.any { it.selected } -> onToggleSelection(true)
|
chapters.fastAny { it.selected } -> onToggleSelection(true)
|
||||||
else -> onChapterClicked(chapterItem.chapter)
|
else -> onChapterClicked(chapterItem.chapter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,17 @@ import eu.kanade.tachiyomi.R
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChapterHeader(
|
fun ChapterHeader(
|
||||||
|
enabled: Boolean,
|
||||||
chapterCount: Int?,
|
chapterCount: Int?,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(onClick = onClick)
|
.clickable(
|
||||||
|
enabled = enabled,
|
||||||
|
onClick = onClick,
|
||||||
|
)
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp),
|
.padding(horizontal = 16.dp, vertical = 4.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.presentation.manga.components
|
package eu.kanade.presentation.manga.components
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@ -23,7 +22,6 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@ -32,6 +30,8 @@ import androidx.compose.ui.unit.sp
|
|||||||
import eu.kanade.presentation.components.ChapterDownloadAction
|
import eu.kanade.presentation.components.ChapterDownloadAction
|
||||||
import eu.kanade.presentation.components.ChapterDownloadIndicator
|
import eu.kanade.presentation.components.ChapterDownloadIndicator
|
||||||
import eu.kanade.presentation.util.ReadItemAlpha
|
import eu.kanade.presentation.util.ReadItemAlpha
|
||||||
|
import eu.kanade.presentation.util.SecondaryItemAlpha
|
||||||
|
import eu.kanade.presentation.util.selectedBackground
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
|
||||||
@ -45,6 +45,7 @@ fun MangaChapterListItem(
|
|||||||
read: Boolean,
|
read: Boolean,
|
||||||
bookmark: Boolean,
|
bookmark: Boolean,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
|
downloadIndicatorEnabled: Boolean,
|
||||||
downloadStateProvider: () -> Download.State,
|
downloadStateProvider: () -> Download.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
@ -53,7 +54,7 @@ fun MangaChapterListItem(
|
|||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(if (selected) MaterialTheme.colorScheme.surfaceVariant else Color.Transparent)
|
.selectedBackground(selected)
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
@ -67,6 +68,7 @@ fun MangaChapterListItem(
|
|||||||
MaterialTheme.colorScheme.onSurface
|
MaterialTheme.colorScheme.onSurface
|
||||||
}
|
}
|
||||||
val textAlpha = remember(read) { if (read) ReadItemAlpha else 1f }
|
val textAlpha = remember(read) { if (read) ReadItemAlpha else 1f }
|
||||||
|
val textSubtitleAlpha = remember(read) { if (read) ReadItemAlpha else SecondaryItemAlpha }
|
||||||
|
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
var textHeight by remember { mutableStateOf(0) }
|
var textHeight by remember { mutableStateOf(0) }
|
||||||
@ -91,7 +93,7 @@ fun MangaChapterListItem(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
Spacer(modifier = Modifier.height(6.dp))
|
||||||
Row(modifier = Modifier.alpha(textAlpha)) {
|
Row(modifier = Modifier.alpha(textSubtitleAlpha)) {
|
||||||
ProvideTextStyle(
|
ProvideTextStyle(
|
||||||
value = MaterialTheme.typography.bodyMedium
|
value = MaterialTheme.typography.bodyMedium
|
||||||
.copy(color = textColor, fontSize = 12.sp),
|
.copy(color = textColor, fontSize = 12.sp),
|
||||||
@ -127,6 +129,7 @@ fun MangaChapterListItem(
|
|||||||
// Download view
|
// Download view
|
||||||
if (onDownloadClick != null) {
|
if (onDownloadClick != null) {
|
||||||
ChapterDownloadIndicator(
|
ChapterDownloadIndicator(
|
||||||
|
enabled = downloadIndicatorEnabled,
|
||||||
modifier = Modifier.padding(start = 4.dp),
|
modifier = Modifier.padding(start = 4.dp),
|
||||||
downloadStateProvider = downloadStateProvider,
|
downloadStateProvider = downloadStateProvider,
|
||||||
downloadProgressProvider = downloadProgressProvider,
|
downloadProgressProvider = downloadProgressProvider,
|
||||||
|
@ -24,11 +24,14 @@ import androidx.compose.material3.IconButton
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.DpOffset
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
@ -82,9 +85,15 @@ fun MangaCoverDialog(
|
|||||||
}
|
}
|
||||||
if (onEditClick != null) {
|
if (onEditClick != null) {
|
||||||
Box {
|
Box {
|
||||||
val (expanded, onExpand) = remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { if (isCustomCover) onExpand(true) else onEditClick(EditCoverAction.EDIT) },
|
onClick = {
|
||||||
|
if (isCustomCover) {
|
||||||
|
expanded = true
|
||||||
|
} else {
|
||||||
|
onEditClick(EditCoverAction.EDIT)
|
||||||
|
}
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Outlined.Edit,
|
imageVector = Icons.Outlined.Edit,
|
||||||
@ -93,20 +102,21 @@ fun MangaCoverDialog(
|
|||||||
}
|
}
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
onDismissRequest = { onExpand(false) },
|
onDismissRequest = { expanded = false },
|
||||||
|
offset = DpOffset(8.dp, 0.dp),
|
||||||
) {
|
) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(text = stringResource(R.string.action_edit)) },
|
text = { Text(text = stringResource(R.string.action_edit)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onEditClick(EditCoverAction.EDIT)
|
onEditClick(EditCoverAction.EDIT)
|
||||||
onExpand(false)
|
expanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(text = stringResource(R.string.action_delete)) },
|
text = { Text(text = stringResource(R.string.action_delete)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onEditClick(EditCoverAction.DELETE)
|
onEditClick(EditCoverAction.DELETE)
|
||||||
onExpand(false)
|
expanded = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,12 @@ package eu.kanade.presentation.manga.components
|
|||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.statusBars
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
import androidx.compose.material.icons.outlined.ArrowBack
|
||||||
import androidx.compose.material.icons.outlined.Close
|
import androidx.compose.material.icons.outlined.Close
|
||||||
import androidx.compose.material.icons.outlined.Download
|
import androidx.compose.material.icons.outlined.Download
|
||||||
import androidx.compose.material.icons.outlined.FilterList
|
import androidx.compose.material.icons.outlined.FilterList
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
import androidx.compose.material.icons.outlined.FlipToBack
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
|
||||||
import androidx.compose.material.icons.outlined.SelectAll
|
import androidx.compose.material.icons.outlined.SelectAll
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@ -30,7 +27,8 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import eu.kanade.presentation.components.AppStateBanners
|
import eu.kanade.presentation.components.AppStateBanners
|
||||||
import eu.kanade.presentation.components.DropdownMenu
|
import eu.kanade.presentation.components.DownloadDropdownMenu
|
||||||
|
import eu.kanade.presentation.components.OverflowMenu
|
||||||
import eu.kanade.presentation.manga.DownloadAction
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
import eu.kanade.presentation.theme.active
|
import eu.kanade.presentation.theme.active
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -101,53 +99,11 @@ fun MangaToolbar(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
val onDismissRequest = { onDownloadExpanded(false) }
|
val onDismissRequest = { onDownloadExpanded(false) }
|
||||||
DropdownMenu(
|
DownloadDropdownMenu(
|
||||||
expanded = downloadExpanded,
|
expanded = downloadExpanded,
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
onDownloadClicked = onClickDownload,
|
||||||
DropdownMenuItem(
|
)
|
||||||
text = { Text(text = stringResource(R.string.download_1)) },
|
|
||||||
onClick = {
|
|
||||||
onClickDownload(DownloadAction.NEXT_1_CHAPTER)
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(R.string.download_5)) },
|
|
||||||
onClick = {
|
|
||||||
onClickDownload(DownloadAction.NEXT_5_CHAPTERS)
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(R.string.download_10)) },
|
|
||||||
onClick = {
|
|
||||||
onClickDownload(DownloadAction.NEXT_10_CHAPTERS)
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(R.string.download_custom)) },
|
|
||||||
onClick = {
|
|
||||||
onClickDownload(DownloadAction.CUSTOM)
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(R.string.download_unread)) },
|
|
||||||
onClick = {
|
|
||||||
onClickDownload(DownloadAction.UNREAD_CHAPTERS)
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(R.string.download_all)) },
|
|
||||||
onClick = {
|
|
||||||
onClickDownload(DownloadAction.ALL_CHAPTERS)
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,49 +112,39 @@ fun MangaToolbar(
|
|||||||
Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint)
|
Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onClickEditCategory != null && onClickMigrate != null) {
|
if (onClickEditCategory != null || onClickMigrate != null || onClickShare != null) {
|
||||||
val (moreExpanded, onMoreExpanded) = remember { mutableStateOf(false) }
|
OverflowMenu { closeMenu ->
|
||||||
Box {
|
if (onClickEditCategory != null) {
|
||||||
IconButton(onClick = { onMoreExpanded(!moreExpanded) }) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Outlined.MoreVert,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_menu_overflow_description),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val onDismissRequest = { onMoreExpanded(false) }
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = moreExpanded,
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(text = stringResource(R.string.action_edit_categories)) },
|
text = { Text(text = stringResource(R.string.action_edit_categories)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onClickEditCategory()
|
onClickEditCategory()
|
||||||
onDismissRequest()
|
closeMenu()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
if (onClickMigrate != null) {
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
text = { Text(text = stringResource(R.string.action_migrate)) },
|
text = { Text(text = stringResource(R.string.action_migrate)) },
|
||||||
onClick = {
|
onClick = {
|
||||||
onClickMigrate()
|
onClickMigrate()
|
||||||
onDismissRequest()
|
closeMenu()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (onClickShare != null) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = { Text(text = stringResource(R.string.action_share)) },
|
||||||
|
onClick = {
|
||||||
|
onClickShare()
|
||||||
|
closeMenu()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if (onClickShare != null) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text = stringResource(R.string.action_share)) },
|
|
||||||
onClick = {
|
|
||||||
onClickShare()
|
|
||||||
onDismissRequest()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
windowInsets = WindowInsets.statusBars,
|
|
||||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme
|
containerColor = MaterialTheme.colorScheme
|
||||||
.surfaceColorAtElevation(3.dp)
|
.surfaceColorAtElevation(3.dp)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package eu.kanade.presentation.more
|
package eu.kanade.presentation.more
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.CloudOff
|
import androidx.compose.material.icons.outlined.CloudOff
|
||||||
@ -21,6 +25,7 @@ import androidx.compose.ui.res.vectorResource
|
|||||||
import eu.kanade.presentation.components.AppStateBanners
|
import eu.kanade.presentation.components.AppStateBanners
|
||||||
import eu.kanade.presentation.components.Divider
|
import eu.kanade.presentation.components.Divider
|
||||||
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
||||||
|
import eu.kanade.presentation.components.WarningBanner
|
||||||
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget
|
||||||
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -32,6 +37,7 @@ import eu.kanade.tachiyomi.widget.TachiyomiBottomNavigationView
|
|||||||
@Composable
|
@Composable
|
||||||
fun MoreScreen(
|
fun MoreScreen(
|
||||||
presenter: MorePresenter,
|
presenter: MorePresenter,
|
||||||
|
isFDroid: Boolean,
|
||||||
onClickDownloadQueue: () -> Unit,
|
onClickDownloadQueue: () -> Unit,
|
||||||
onClickCategories: () -> Unit,
|
onClickCategories: () -> Unit,
|
||||||
onClickBackupAndRestore: () -> Unit,
|
onClickBackupAndRestore: () -> Unit,
|
||||||
@ -43,8 +49,21 @@ fun MoreScreen(
|
|||||||
|
|
||||||
ScrollbarLazyColumn(
|
ScrollbarLazyColumn(
|
||||||
modifier = Modifier.statusBarsPadding(),
|
modifier = Modifier.statusBarsPadding(),
|
||||||
contentPadding = TachiyomiBottomNavigationView.withBottomNavPadding(),
|
contentPadding = TachiyomiBottomNavigationView.withBottomNavPadding(
|
||||||
|
WindowInsets.navigationBars.asPaddingValues(),
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
|
if (isFDroid) {
|
||||||
|
item {
|
||||||
|
WarningBanner(
|
||||||
|
textRes = R.string.fdroid_warning,
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
uriHandler.openUri("https://tachiyomi.org/help/faq/#how-do-i-migrate-from-the-f-droid-version")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
LogoHeader()
|
LogoHeader()
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.util.fastMap
|
||||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||||
import cafe.adriel.voyager.core.model.coroutineScope
|
import cafe.adriel.voyager.core.model.coroutineScope
|
||||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||||
@ -240,14 +241,14 @@ private class ClearDatabaseScreenModel : StateScreenModel<ClearDatabaseScreenMod
|
|||||||
|
|
||||||
fun selectAll() = mutableState.update { state ->
|
fun selectAll() = mutableState.update { state ->
|
||||||
if (state !is State.Ready) return@update state
|
if (state !is State.Ready) return@update state
|
||||||
state.copy(selection = state.items.map { it.id })
|
state.copy(selection = state.items.fastMap { it.id })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun invertSelection() = mutableState.update { state ->
|
fun invertSelection() = mutableState.update { state ->
|
||||||
if (state !is State.Ready) return@update state
|
if (state !is State.Ready) return@update state
|
||||||
state.copy(
|
state.copy(
|
||||||
selection = state.items
|
selection = state.items
|
||||||
.map { it.id }
|
.fastMap { it.id }
|
||||||
.filterNot { it in state.selection },
|
.filterNot { it in state.selection },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.util.fastMap
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.domain.category.interactor.GetCategories
|
import eu.kanade.domain.category.interactor.GetCategories
|
||||||
@ -204,8 +205,8 @@ class SettingsDownloadScreen : SearchableSettings {
|
|||||||
itemLabel = { it.visualName },
|
itemLabel = { it.visualName },
|
||||||
onDismissRequest = { showDialog = false },
|
onDismissRequest = { showDialog = false },
|
||||||
onValueChanged = { newIncluded, newExcluded ->
|
onValueChanged = { newIncluded, newExcluded ->
|
||||||
downloadNewChapterCategoriesPref.set(newIncluded.map { it.id.toString() }.toSet())
|
downloadNewChapterCategoriesPref.set(newIncluded.fastMap { it.id.toString() }.toSet())
|
||||||
downloadNewChapterCategoriesExcludePref.set(newExcluded.map { it.id.toString() }.toSet())
|
downloadNewChapterCategoriesExcludePref.set(newExcluded.fastMap { it.id.toString() }.toSet())
|
||||||
showDialog = false
|
showDialog = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -25,6 +25,7 @@ import androidx.compose.ui.draw.clipToBounds
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
import androidx.compose.ui.res.pluralStringResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.util.fastMap
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
@ -124,9 +125,9 @@ class SettingsLibraryScreen : SearchableSettings {
|
|||||||
|
|
||||||
// For default category
|
// For default category
|
||||||
val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) +
|
val ids = listOf(libraryPreferences.defaultCategory().defaultValue()) +
|
||||||
allCategories.map { it.id.toInt() }
|
allCategories.fastMap { it.id.toInt() }
|
||||||
val labels = listOf(stringResource(R.string.default_category_summary)) +
|
val labels = listOf(stringResource(R.string.default_category_summary)) +
|
||||||
allCategories.map { it.visualName(context) }
|
allCategories.fastMap { it.visualName(context) }
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(R.string.categories),
|
title = stringResource(R.string.categories),
|
||||||
|
@ -44,43 +44,42 @@ internal fun BasePreferenceWidget(
|
|||||||
widget: @Composable (() -> Unit)? = null,
|
widget: @Composable (() -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val highlighted = LocalPreferenceHighlighted.current
|
val highlighted = LocalPreferenceHighlighted.current
|
||||||
Box(modifier = Modifier.highlightBackground(highlighted)) {
|
Row(
|
||||||
Row(
|
modifier = modifier
|
||||||
modifier = modifier
|
.highlightBackground(highlighted)
|
||||||
.sizeIn(minHeight = 56.dp)
|
.sizeIn(minHeight = 56.dp)
|
||||||
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
.clickable(enabled = onClick != null, onClick = { onClick?.invoke() })
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
if (icon != null) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(start = PrefsHorizontalPadding, end = 8.dp),
|
||||||
|
content = { icon() },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(vertical = PrefsVerticalPadding),
|
||||||
) {
|
) {
|
||||||
if (icon != null) {
|
if (!title.isNullOrBlank()) {
|
||||||
Box(
|
Text(
|
||||||
modifier = Modifier.padding(start = PrefsHorizontalPadding, end = 8.dp),
|
modifier = Modifier.padding(horizontal = PrefsHorizontalPadding),
|
||||||
content = { icon() },
|
text = title,
|
||||||
)
|
overflow = TextOverflow.Ellipsis,
|
||||||
}
|
maxLines = 2,
|
||||||
Column(
|
style = MaterialTheme.typography.titleLarge,
|
||||||
modifier = Modifier
|
fontSize = TitleFontSize,
|
||||||
.weight(1f)
|
|
||||||
.padding(vertical = PrefsVerticalPadding),
|
|
||||||
) {
|
|
||||||
if (!title.isNullOrBlank()) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.padding(horizontal = PrefsHorizontalPadding),
|
|
||||||
text = title,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
maxLines = 2,
|
|
||||||
style = MaterialTheme.typography.titleLarge,
|
|
||||||
fontSize = TitleFontSize,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
subcomponent?.invoke(this)
|
|
||||||
}
|
|
||||||
if (widget != null) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.padding(end = PrefsHorizontalPadding),
|
|
||||||
content = { widget() },
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
subcomponent?.invoke(this)
|
||||||
|
}
|
||||||
|
if (widget != null) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(end = PrefsHorizontalPadding),
|
||||||
|
content = { widget() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,18 +28,18 @@ fun EditTextPreferenceWidget(
|
|||||||
value: String,
|
value: String,
|
||||||
onConfirm: suspend (String) -> Boolean,
|
onConfirm: suspend (String) -> Boolean,
|
||||||
) {
|
) {
|
||||||
val (isDialogShown, showDialog) = remember { mutableStateOf(false) }
|
var isDialogShown by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
title = title,
|
title = title,
|
||||||
subtitle = subtitle?.format(value),
|
subtitle = subtitle?.format(value),
|
||||||
icon = icon,
|
icon = icon,
|
||||||
onPreferenceClick = { showDialog(true) },
|
onPreferenceClick = { isDialogShown = true },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isDialogShown) {
|
if (isDialogShown) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val onDismissRequest = { showDialog(false) }
|
val onDismissRequest = { isDialogShown = false }
|
||||||
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||||
mutableStateOf(TextFieldValue(value))
|
mutableStateOf(TextFieldValue(value))
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,10 @@ import androidx.compose.material3.RadioButton
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@ -36,18 +38,18 @@ fun <T> ListPreferenceWidget(
|
|||||||
entries: Map<out T, String>,
|
entries: Map<out T, String>,
|
||||||
onValueChange: (T) -> Unit,
|
onValueChange: (T) -> Unit,
|
||||||
) {
|
) {
|
||||||
val (isDialogShown, showDialog) = remember { mutableStateOf(false) }
|
var isDialogShown by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
title = title,
|
title = title,
|
||||||
subtitle = subtitle,
|
subtitle = subtitle,
|
||||||
icon = icon,
|
icon = icon,
|
||||||
onPreferenceClick = { showDialog(true) },
|
onPreferenceClick = { isDialogShown = true },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isDialogShown) {
|
if (isDialogShown) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { showDialog(false) },
|
onDismissRequest = { isDialogShown = false },
|
||||||
title = { Text(text = title) },
|
title = { Text(text = title) },
|
||||||
text = {
|
text = {
|
||||||
Box {
|
Box {
|
||||||
@ -61,7 +63,7 @@ fun <T> ListPreferenceWidget(
|
|||||||
isSelected = isSelected,
|
isSelected = isSelected,
|
||||||
onSelected = {
|
onSelected = {
|
||||||
onValueChange(current.key!!)
|
onValueChange(current.key!!)
|
||||||
showDialog(false)
|
isDialogShown = false
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -72,7 +74,7 @@ fun <T> ListPreferenceWidget(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(onClick = { showDialog(false) }) {
|
TextButton(onClick = { isDialogShown = false }) {
|
||||||
Text(text = stringResource(R.string.action_cancel))
|
Text(text = stringResource(R.string.action_cancel))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -11,8 +11,10 @@ import androidx.compose.material3.MaterialTheme
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.toMutableStateList
|
import androidx.compose.runtime.toMutableStateList
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -30,13 +32,13 @@ fun MultiSelectListPreferenceWidget(
|
|||||||
values: Set<String>,
|
values: Set<String>,
|
||||||
onValuesChange: (Set<String>) -> Unit,
|
onValuesChange: (Set<String>) -> Unit,
|
||||||
) {
|
) {
|
||||||
val (isDialogShown, showDialog) = remember { mutableStateOf(false) }
|
var isDialogShown by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
title = preference.title,
|
title = preference.title,
|
||||||
subtitle = preference.subtitleProvider(values, preference.entries),
|
subtitle = preference.subtitleProvider(values, preference.entries),
|
||||||
icon = preference.icon,
|
icon = preference.icon,
|
||||||
onPreferenceClick = { showDialog(true) },
|
onPreferenceClick = { isDialogShown = true },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isDialogShown) {
|
if (isDialogShown) {
|
||||||
@ -46,7 +48,7 @@ fun MultiSelectListPreferenceWidget(
|
|||||||
.toMutableStateList()
|
.toMutableStateList()
|
||||||
}
|
}
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { showDialog(false) },
|
onDismissRequest = { isDialogShown = false },
|
||||||
title = { Text(text = preference.title) },
|
title = { Text(text = preference.title) },
|
||||||
text = {
|
text = {
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
@ -91,14 +93,14 @@ fun MultiSelectListPreferenceWidget(
|
|||||||
TextButton(
|
TextButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
onValuesChange(selected.toMutableSet())
|
onValuesChange(selected.toMutableSet())
|
||||||
showDialog(false)
|
isDialogShown = false
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(android.R.string.ok))
|
Text(text = stringResource(android.R.string.ok))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
TextButton(onClick = { showDialog(false) }) {
|
TextButton(onClick = { isDialogShown = false }) {
|
||||||
Text(text = stringResource(R.string.action_cancel))
|
Text(text = stringResource(R.string.action_cancel))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SwitchPreferenceWidget(
|
fun SwitchPreferenceWidget(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
title: String,
|
title: String,
|
||||||
subtitle: String? = null,
|
subtitle: String? = null,
|
||||||
icon: ImageVector? = null,
|
icon: ImageVector? = null,
|
||||||
@ -21,6 +22,7 @@ fun SwitchPreferenceWidget(
|
|||||||
onCheckedChanged: (Boolean) -> Unit,
|
onCheckedChanged: (Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
TextPreferenceWidget(
|
TextPreferenceWidget(
|
||||||
|
modifier = modifier,
|
||||||
title = title,
|
title = title,
|
||||||
subtitle = subtitle,
|
subtitle = subtitle,
|
||||||
icon = icon,
|
icon = icon,
|
||||||
|
@ -2,11 +2,8 @@ package eu.kanade.presentation.updates
|
|||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.calculateEndPadding
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.FlipToBack
|
import androidx.compose.material.icons.outlined.FlipToBack
|
||||||
import androidx.compose.material.icons.outlined.Refresh
|
import androidx.compose.material.icons.outlined.Refresh
|
||||||
@ -23,17 +20,17 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.util.fastAll
|
||||||
|
import androidx.compose.ui.util.fastAny
|
||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.ChapterDownloadAction
|
import eu.kanade.presentation.components.ChapterDownloadAction
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.presentation.components.LazyColumn
|
import eu.kanade.presentation.components.FastScrollLazyColumn
|
||||||
import eu.kanade.presentation.components.LoadingScreen
|
import eu.kanade.presentation.components.LoadingScreen
|
||||||
import eu.kanade.presentation.components.MangaBottomActionMenu
|
import eu.kanade.presentation.components.MangaBottomActionMenu
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.components.SwipeRefresh
|
import eu.kanade.presentation.components.SwipeRefresh
|
||||||
import eu.kanade.presentation.components.VerticalFastScroller
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
@ -124,7 +121,6 @@ private fun UpdateScreenContent(
|
|||||||
onClickCover: (UpdatesItem) -> Unit,
|
onClickCover: (UpdatesItem) -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val updatesListState = rememberLazyListState()
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
var isRefreshing by remember { mutableStateOf(false) }
|
var isRefreshing by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
@ -143,34 +139,26 @@ private fun UpdateScreenContent(
|
|||||||
enabled = presenter.selectionMode.not(),
|
enabled = presenter.selectionMode.not(),
|
||||||
indicatorPadding = contentPadding,
|
indicatorPadding = contentPadding,
|
||||||
) {
|
) {
|
||||||
VerticalFastScroller(
|
FastScrollLazyColumn(
|
||||||
listState = updatesListState,
|
contentPadding = contentPadding,
|
||||||
topContentPadding = contentPadding.calculateTopPadding(),
|
|
||||||
endContentPadding = contentPadding.calculateEndPadding(LocalLayoutDirection.current),
|
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
if (presenter.lastUpdated > 0L) {
|
||||||
modifier = Modifier.fillMaxHeight(),
|
updatesLastUpdatedItem(presenter.lastUpdated)
|
||||||
state = updatesListState,
|
|
||||||
contentPadding = contentPadding,
|
|
||||||
) {
|
|
||||||
if (presenter.lastUpdated > 0L) {
|
|
||||||
updatesLastUpdatedItem(presenter.lastUpdated)
|
|
||||||
}
|
|
||||||
|
|
||||||
updatesUiItems(
|
|
||||||
uiModels = presenter.uiModels,
|
|
||||||
selectionMode = presenter.selectionMode,
|
|
||||||
onUpdateSelected = presenter::toggleSelection,
|
|
||||||
onClickCover = onClickCover,
|
|
||||||
onClickUpdate = {
|
|
||||||
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
|
|
||||||
context.startActivity(intent)
|
|
||||||
},
|
|
||||||
onDownloadChapter = presenter::downloadChapters,
|
|
||||||
relativeTime = presenter.relativeTime,
|
|
||||||
dateFormat = presenter.dateFormat,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updatesUiItems(
|
||||||
|
uiModels = presenter.uiModels,
|
||||||
|
selectionMode = presenter.selectionMode,
|
||||||
|
onUpdateSelected = presenter::toggleSelection,
|
||||||
|
onClickCover = onClickCover,
|
||||||
|
onClickUpdate = {
|
||||||
|
val intent = ReaderActivity.newIntent(context, it.update.mangaId, it.update.chapterId)
|
||||||
|
context.startActivity(intent)
|
||||||
|
},
|
||||||
|
onDownloadChapter = presenter::downloadChapters,
|
||||||
|
relativeTime = presenter.relativeTime,
|
||||||
|
dateFormat = presenter.dateFormat,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,24 +243,24 @@ private fun UpdatesBottomBar(
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onBookmarkClicked = {
|
onBookmarkClicked = {
|
||||||
onMultiBookmarkClicked.invoke(selected, true)
|
onMultiBookmarkClicked.invoke(selected, true)
|
||||||
}.takeIf { selected.any { !it.update.bookmark } },
|
}.takeIf { selected.fastAny { !it.update.bookmark } },
|
||||||
onRemoveBookmarkClicked = {
|
onRemoveBookmarkClicked = {
|
||||||
onMultiBookmarkClicked.invoke(selected, false)
|
onMultiBookmarkClicked.invoke(selected, false)
|
||||||
}.takeIf { selected.all { it.update.bookmark } },
|
}.takeIf { selected.fastAll { it.update.bookmark } },
|
||||||
onMarkAsReadClicked = {
|
onMarkAsReadClicked = {
|
||||||
onMultiMarkAsReadClicked(selected, true)
|
onMultiMarkAsReadClicked(selected, true)
|
||||||
}.takeIf { selected.any { !it.update.read } },
|
}.takeIf { selected.fastAny { !it.update.read } },
|
||||||
onMarkAsUnreadClicked = {
|
onMarkAsUnreadClicked = {
|
||||||
onMultiMarkAsReadClicked(selected, false)
|
onMultiMarkAsReadClicked(selected, false)
|
||||||
}.takeIf { selected.any { it.update.read } },
|
}.takeIf { selected.fastAny { it.update.read } },
|
||||||
onDownloadClicked = {
|
onDownloadClicked = {
|
||||||
onDownloadChapter(selected, ChapterDownloadAction.START)
|
onDownloadChapter(selected, ChapterDownloadAction.START)
|
||||||
}.takeIf {
|
}.takeIf {
|
||||||
selected.any { it.downloadStateProvider() != Download.State.DOWNLOADED }
|
selected.fastAny { it.downloadStateProvider() != Download.State.DOWNLOADED }
|
||||||
},
|
},
|
||||||
onDeleteClicked = {
|
onDeleteClicked = {
|
||||||
onMultiDeleteClicked(selected)
|
onMultiDeleteClicked(selected)
|
||||||
}.takeIf { selected.any { it.downloadStateProvider() == Download.State.DOWNLOADED } },
|
}.takeIf { selected.fastAny { it.downloadStateProvider() == Download.State.DOWNLOADED } },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.presentation.updates
|
package eu.kanade.presentation.updates
|
||||||
|
|
||||||
import android.text.format.DateUtils
|
import android.text.format.DateUtils
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -28,7 +27,6 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
@ -43,6 +41,7 @@ import eu.kanade.presentation.components.MangaCover
|
|||||||
import eu.kanade.presentation.components.RelativeDateHeader
|
import eu.kanade.presentation.components.RelativeDateHeader
|
||||||
import eu.kanade.presentation.util.ReadItemAlpha
|
import eu.kanade.presentation.util.ReadItemAlpha
|
||||||
import eu.kanade.presentation.util.horizontalPadding
|
import eu.kanade.presentation.util.horizontalPadding
|
||||||
|
import eu.kanade.presentation.util.selectedBackground
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesItem
|
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesItem
|
||||||
@ -135,6 +134,7 @@ fun LazyListScope.updatesUiItems(
|
|||||||
onDownloadChapter = {
|
onDownloadChapter = {
|
||||||
if (selectionMode.not()) onDownloadChapter(listOf(updatesItem), it)
|
if (selectionMode.not()) onDownloadChapter(listOf(updatesItem), it)
|
||||||
},
|
},
|
||||||
|
downloadIndicatorEnabled = selectionMode.not(),
|
||||||
downloadStateProvider = updatesItem.downloadStateProvider,
|
downloadStateProvider = updatesItem.downloadStateProvider,
|
||||||
downloadProgressProvider = updatesItem.downloadProgressProvider,
|
downloadProgressProvider = updatesItem.downloadProgressProvider,
|
||||||
)
|
)
|
||||||
@ -153,13 +153,14 @@ fun UpdatesUiItem(
|
|||||||
onClickCover: () -> Unit,
|
onClickCover: () -> Unit,
|
||||||
onDownloadChapter: (ChapterDownloadAction) -> Unit,
|
onDownloadChapter: (ChapterDownloadAction) -> Unit,
|
||||||
// Download Indicator
|
// Download Indicator
|
||||||
|
downloadIndicatorEnabled: Boolean,
|
||||||
downloadStateProvider: () -> Download.State,
|
downloadStateProvider: () -> Download.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
) {
|
) {
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.background(if (selected) MaterialTheme.colorScheme.surfaceVariant else Color.Transparent)
|
.selectedBackground(selected)
|
||||||
.combinedClickable(
|
.combinedClickable(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
@ -225,6 +226,7 @@ fun UpdatesUiItem(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChapterDownloadIndicator(
|
ChapterDownloadIndicator(
|
||||||
|
enabled = downloadIndicatorEnabled,
|
||||||
modifier = Modifier.padding(start = 4.dp),
|
modifier = Modifier.padding(start = 4.dp),
|
||||||
downloadStateProvider = downloadStateProvider,
|
downloadStateProvider = downloadStateProvider,
|
||||||
downloadProgressProvider = downloadProgressProvider,
|
downloadProgressProvider = downloadProgressProvider,
|
||||||
|
@ -12,3 +12,4 @@ val verticalPadding = vertical
|
|||||||
val topPaddingValues = PaddingValues(top = vertical)
|
val topPaddingValues = PaddingValues(top = vertical)
|
||||||
|
|
||||||
const val ReadItemAlpha = .38f
|
const val ReadItemAlpha = .38f
|
||||||
|
const val SecondaryItemAlpha = .78f
|
||||||
|
@ -29,7 +29,7 @@ fun Modifier.selectedBackground(isSelected: Boolean): Modifier = composed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Modifier.secondaryItemAlpha(): Modifier = this.alpha(.78f)
|
fun Modifier.secondaryItemAlpha(): Modifier = this.alpha(SecondaryItemAlpha)
|
||||||
|
|
||||||
fun Modifier.clickableNoIndication(
|
fun Modifier.clickableNoIndication(
|
||||||
onLongClick: (() -> Unit)? = null,
|
onLongClick: (() -> Unit)? = null,
|
||||||
|
@ -244,6 +244,10 @@ class Downloader(
|
|||||||
* @param autoStart whether to start the downloader after enqueing the chapters.
|
* @param autoStart whether to start the downloader after enqueing the chapters.
|
||||||
*/
|
*/
|
||||||
fun queueChapters(manga: Manga, chapters: List<Chapter>, autoStart: Boolean) = launchIO {
|
fun queueChapters(manga: Manga, chapters: List<Chapter>, autoStart: Boolean) = launchIO {
|
||||||
|
if (chapters.isEmpty()) {
|
||||||
|
return@launchIO
|
||||||
|
}
|
||||||
|
|
||||||
val source = sourceManager.get(manga.source) as? HttpSource ?: return@launchIO
|
val source = sourceManager.get(manga.source) as? HttpSource ?: return@launchIO
|
||||||
val wasEmpty = queue.isEmpty()
|
val wasEmpty = queue.isEmpty()
|
||||||
// Called in background thread, the operation can be slow with SAF.
|
// Called in background thread, the operation can be slow with SAF.
|
||||||
|
@ -415,8 +415,7 @@ class LibraryUpdateService(
|
|||||||
private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
private fun downloadChapters(manga: Manga, chapters: List<Chapter>) {
|
||||||
// We don't want to start downloading while the library is updating, because websites
|
// We don't want to start downloading while the library is updating, because websites
|
||||||
// may don't like it and they could ban the user.
|
// may don't like it and they could ban the user.
|
||||||
val dbChapters = chapters.map { it.toDbChapter() }
|
downloadManager.downloadChapters(manga, chapters.map { it.toDbChapter() }, false)
|
||||||
downloadManager.downloadChapters(manga, dbChapters, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -271,11 +271,9 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
*/
|
*/
|
||||||
private fun downloadChapters(chapterUrls: Array<String>, mangaId: Long) {
|
private fun downloadChapters(chapterUrls: Array<String>, mangaId: Long) {
|
||||||
launchIO {
|
launchIO {
|
||||||
val manga = getManga.await(mangaId)
|
val manga = getManga.await(mangaId) ?: return@launchIO
|
||||||
val chapters = chapterUrls.mapNotNull { getChapter.await(it, mangaId)?.toDbChapter() }
|
val chapters = chapterUrls.mapNotNull { getChapter.await(it, mangaId)?.toDbChapter() }
|
||||||
if (manga != null && chapters.isNotEmpty()) {
|
downloadManager.downloadChapters(manga, chapters)
|
||||||
downloadManager.downloadChapters(manga, chapters)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
|
|||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.network.parseAs
|
import eu.kanade.tachiyomi.network.parseAs
|
||||||
import eu.kanade.tachiyomi.util.lang.withIOContext
|
import eu.kanade.tachiyomi.util.lang.withIOContext
|
||||||
import eu.kanade.tachiyomi.util.system.getInstallerPackageName
|
import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -38,7 +38,7 @@ class AppUpdateChecker {
|
|||||||
|
|
||||||
// Check if latest version is different from current version
|
// Check if latest version is different from current version
|
||||||
if (isNewVersion(it.version)) {
|
if (isNewVersion(it.version)) {
|
||||||
if (context.getInstallerPackageName() == "org.fdroid.fdroid") {
|
if (context.isInstalledFromFDroid()) {
|
||||||
AppUpdateResult.NewUpdateFdroidInstallation
|
AppUpdateResult.NewUpdateFdroidInstallation
|
||||||
} else {
|
} else {
|
||||||
AppUpdateResult.NewUpdate(it)
|
AppUpdateResult.NewUpdate(it)
|
||||||
|
@ -32,13 +32,7 @@ class SourceManager(
|
|||||||
|
|
||||||
private val scope = CoroutineScope(Job() + Dispatchers.IO)
|
private val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||||
|
|
||||||
private var sourcesMap = ConcurrentHashMap<Long, Source>()
|
private val sourcesMapFlow = MutableStateFlow(ConcurrentHashMap<Long, Source>())
|
||||||
set(value) {
|
|
||||||
field = value
|
|
||||||
sourcesMapFlow.value = field
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sourcesMapFlow = MutableStateFlow(sourcesMap)
|
|
||||||
|
|
||||||
private val stubSourcesMap = ConcurrentHashMap<Long, StubSource>()
|
private val stubSourcesMap = ConcurrentHashMap<Long, StubSource>()
|
||||||
|
|
||||||
@ -56,7 +50,7 @@ class SourceManager(
|
|||||||
registerStubSource(it.toSourceData())
|
registerStubSource(it.toSourceData())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourcesMap = mutableMap
|
sourcesMapFlow.value = mutableMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,18 +66,18 @@ class SourceManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun get(sourceKey: Long): Source? {
|
fun get(sourceKey: Long): Source? {
|
||||||
return sourcesMap[sourceKey]
|
return sourcesMapFlow.value[sourceKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOrStub(sourceKey: Long): Source {
|
fun getOrStub(sourceKey: Long): Source {
|
||||||
return sourcesMap[sourceKey] ?: stubSourcesMap.getOrPut(sourceKey) {
|
return sourcesMapFlow.value[sourceKey] ?: stubSourcesMap.getOrPut(sourceKey) {
|
||||||
runBlocking { createStubSource(sourceKey) }
|
runBlocking { createStubSource(sourceKey) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOnlineSources() = sourcesMap.values.filterIsInstance<HttpSource>()
|
fun getOnlineSources() = sourcesMapFlow.value.values.filterIsInstance<HttpSource>()
|
||||||
|
|
||||||
fun getCatalogueSources() = sourcesMap.values.filterIsInstance<CatalogueSource>()
|
fun getCatalogueSources() = sourcesMapFlow.value.values.filterIsInstance<CatalogueSource>()
|
||||||
|
|
||||||
fun getStubSources(): List<StubSource> {
|
fun getStubSources(): List<StubSource> {
|
||||||
val onlineSourceIds = getOnlineSources().map { it.id }
|
val onlineSourceIds = getOnlineSources().map { it.id }
|
||||||
|
@ -45,7 +45,6 @@ class BrowseController : FullComposeController<BrowsePresenter>, RootController
|
|||||||
startIndex = 1.takeIf { toExtensions },
|
startIndex = 1.takeIf { toExtensions },
|
||||||
searchQuery = query,
|
searchQuery = query,
|
||||||
onChangeSearchQuery = { presenter.extensionsPresenter.search(it) },
|
onChangeSearchQuery = { presenter.extensionsPresenter.search(it) },
|
||||||
placeholderRes = R.string.action_search_hint,
|
|
||||||
incognitoMode = presenter.isIncognitoMode,
|
incognitoMode = presenter.isIncognitoMode,
|
||||||
downloadedOnlyMode = presenter.isDownloadOnly,
|
downloadedOnlyMode = presenter.isDownloadOnly,
|
||||||
)
|
)
|
||||||
|
@ -13,7 +13,6 @@ import kotlinx.coroutines.channels.Channel
|
|||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -36,7 +35,6 @@ class ExtensionFilterPresenter(
|
|||||||
logcat(LogPriority.ERROR, exception)
|
logcat(LogPriority.ERROR, exception)
|
||||||
_events.send(Event.FailedFetchingLanguages)
|
_events.send(Event.FailedFetchingLanguages)
|
||||||
}
|
}
|
||||||
.stateIn(presenterScope)
|
|
||||||
.collectLatest(::collectLatestSourceLangMap)
|
.collectLatest(::collectLatestSourceLangMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
|
|||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@ -22,7 +23,7 @@ import kotlinx.coroutines.flow.collectLatest
|
|||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@ -116,7 +117,7 @@ class ExtensionsPresenter(
|
|||||||
|
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
.stateIn(presenterScope)
|
.onStart { delay(500) } // Defer to avoid crashing on initial render
|
||||||
.collectLatest {
|
.collectLatest {
|
||||||
state.isLoading = false
|
state.isLoading = false
|
||||||
state.items = it
|
state.items = it
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.extension
|
package eu.kanade.tachiyomi.ui.browse.extension
|
||||||
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Search
|
|
||||||
import androidx.compose.material.icons.outlined.Translate
|
import androidx.compose.material.icons.outlined.Translate
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -21,13 +20,8 @@ fun extensionsTab(
|
|||||||
) = TabContent(
|
) = TabContent(
|
||||||
titleRes = R.string.label_extensions,
|
titleRes = R.string.label_extensions,
|
||||||
badgeNumber = presenter.updates.takeIf { it > 0 },
|
badgeNumber = presenter.updates.takeIf { it > 0 },
|
||||||
|
searchEnabled = true,
|
||||||
actions = listOf(
|
actions = listOf(
|
||||||
AppBar.Action(
|
|
||||||
title = stringResource(R.string.action_search),
|
|
||||||
icon = Icons.Outlined.Search,
|
|
||||||
onClick = { presenter.search("") },
|
|
||||||
),
|
|
||||||
|
|
||||||
AppBar.Action(
|
AppBar.Action(
|
||||||
title = stringResource(R.string.action_filter),
|
title = stringResource(R.string.action_filter),
|
||||||
icon = Icons.Outlined.Translate,
|
icon = Icons.Outlined.Translate,
|
||||||
|
@ -15,7 +15,6 @@ import kotlinx.coroutines.channels.Channel
|
|||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -40,7 +39,6 @@ class SourcesFilterPresenter(
|
|||||||
logcat(LogPriority.ERROR, exception)
|
logcat(LogPriority.ERROR, exception)
|
||||||
_events.send(Event.FailedFetchingLanguages)
|
_events.send(Event.FailedFetchingLanguages)
|
||||||
}
|
}
|
||||||
.stateIn(presenterScope)
|
|
||||||
.collectLatest(::collectLatestSourceLangMap)
|
.collectLatest(::collectLatestSourceLangMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,10 +14,11 @@ import eu.kanade.tachiyomi.util.lang.launchIO
|
|||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -43,7 +44,7 @@ class SourcesPresenter(
|
|||||||
logcat(LogPriority.ERROR, exception)
|
logcat(LogPriority.ERROR, exception)
|
||||||
_events.send(Event.FailedFetchingSources)
|
_events.send(Event.FailedFetchingSources)
|
||||||
}
|
}
|
||||||
.stateIn(presenterScope)
|
.onStart { delay(500) } // Defer to avoid crashing on initial render
|
||||||
.collectLatest(::collectLatestSources)
|
.collectLatest(::collectLatestSources)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,11 +119,7 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||||||
|
|
||||||
private fun navigateUp() {
|
private fun navigateUp() {
|
||||||
when {
|
when {
|
||||||
presenter.searchQuery != null -> presenter.searchQuery = null
|
!presenter.isUserQuery && presenter.searchQuery != null -> presenter.searchQuery = null
|
||||||
presenter.isUserQuery -> {
|
|
||||||
val (_, filters) = presenter.currentFilter as BrowseSourcePresenter.Filter.UserInput
|
|
||||||
presenter.search(query = "", filters = filters)
|
|
||||||
}
|
|
||||||
else -> router.popCurrentController()
|
else -> router.popCurrentController()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ open class BrowseSourcePresenter(
|
|||||||
.map {
|
.map {
|
||||||
it.map { sManga ->
|
it.map { sManga ->
|
||||||
withIOContext {
|
withIOContext {
|
||||||
networkToLocalManga.await(sManga.toDomainManga(), sourceId)
|
networkToLocalManga.await(sManga.toDomainManga(sourceId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,15 +154,15 @@ open class BrowseSourcePresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
state.filters = source!!.getFilterList()
|
val source = source ?: return
|
||||||
if (currentFilter !is Filter.UserInput) return
|
state.filters = source.getFilterList()
|
||||||
state.currentFilter = (currentFilter as Filter.UserInput).copy(filters = state.filters)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(query: String? = null, filters: FilterList? = null) {
|
fun search(query: String? = null, filters: FilterList? = null) {
|
||||||
Filter.valueOf(query ?: "").let {
|
Filter.valueOf(query ?: "").let {
|
||||||
if (it !is Filter.UserInput) {
|
if (it !is Filter.UserInput) {
|
||||||
state.currentFilter = it
|
state.currentFilter = it
|
||||||
|
state.searchQuery = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,6 +260,6 @@ open class GlobalSearchPresenter(
|
|||||||
* @return a manga from the database.
|
* @return a manga from the database.
|
||||||
*/
|
*/
|
||||||
protected open suspend fun networkToLocalManga(sManga: SManga, sourceId: Long): DomainManga {
|
protected open suspend fun networkToLocalManga(sManga: SManga, sourceId: Long): DomainManga {
|
||||||
return networkToLocalManga.await(sManga.toDomainManga(), sourceId)
|
return networkToLocalManga.await(sManga.toDomainManga(sourceId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,9 @@ import androidx.compose.foundation.layout.navigationBarsPadding
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material.icons.outlined.MoreVert
|
|
||||||
import androidx.compose.material.icons.outlined.Pause
|
import androidx.compose.material.icons.outlined.Pause
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
@ -52,6 +50,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import eu.kanade.presentation.components.AppBar
|
import eu.kanade.presentation.components.AppBar
|
||||||
import eu.kanade.presentation.components.EmptyScreen
|
import eu.kanade.presentation.components.EmptyScreen
|
||||||
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
import eu.kanade.presentation.components.ExtendedFloatingActionButton
|
||||||
|
import eu.kanade.presentation.components.OverflowMenu
|
||||||
import eu.kanade.presentation.components.Pill
|
import eu.kanade.presentation.components.Pill
|
||||||
import eu.kanade.presentation.components.Scaffold
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -61,7 +60,6 @@ import eu.kanade.tachiyomi.databinding.DownloadListBinding
|
|||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
|
import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
|
||||||
import eu.kanade.tachiyomi.util.lang.launchUI
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import me.saket.cascade.CascadeDropdownMenu
|
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -147,69 +145,69 @@ class DownloadController :
|
|||||||
navigateUp = router::popCurrentController,
|
navigateUp = router::popCurrentController,
|
||||||
actions = {
|
actions = {
|
||||||
if (downloadList.isNotEmpty()) {
|
if (downloadList.isNotEmpty()) {
|
||||||
val (expanded, onExpanded) = remember { mutableStateOf(false) }
|
OverflowMenu { closeMenu ->
|
||||||
Box {
|
DropdownMenuItem(
|
||||||
IconButton(onClick = { onExpanded(!expanded) }) {
|
text = { Text(text = stringResource(R.string.action_reorganize_by)) },
|
||||||
Icon(
|
children = {
|
||||||
imageVector = Icons.Outlined.MoreVert,
|
DropdownMenuItem(
|
||||||
contentDescription = stringResource(R.string.abc_action_menu_overflow_description),
|
text = { Text(text = stringResource(R.string.action_order_by_upload_date)) },
|
||||||
)
|
children = {
|
||||||
}
|
DropdownMenuItem(
|
||||||
CascadeDropdownMenu(
|
text = { Text(text = stringResource(R.string.action_newest)) },
|
||||||
expanded = expanded,
|
onClick = {
|
||||||
onDismissRequest = { onExpanded(false) },
|
reorderQueue(
|
||||||
) {
|
{ it.download.chapter.date_upload },
|
||||||
DropdownMenuItem(
|
true,
|
||||||
text = { Text(text = stringResource(R.string.action_reorganize_by)) },
|
)
|
||||||
children = {
|
closeMenu()
|
||||||
DropdownMenuItem(
|
},
|
||||||
text = { Text(text = stringResource(R.string.action_order_by_upload_date)) },
|
)
|
||||||
children = {
|
DropdownMenuItem(
|
||||||
DropdownMenuItem(
|
text = { Text(text = stringResource(R.string.action_oldest)) },
|
||||||
text = { Text(text = stringResource(R.string.action_newest)) },
|
onClick = {
|
||||||
onClick = {
|
reorderQueue(
|
||||||
reorderQueue({ it.download.chapter.date_upload }, true)
|
{ it.download.chapter.date_upload },
|
||||||
onExpanded(false)
|
false,
|
||||||
},
|
)
|
||||||
)
|
closeMenu()
|
||||||
DropdownMenuItem(
|
},
|
||||||
text = { Text(text = stringResource(R.string.action_oldest)) },
|
)
|
||||||
onClick = {
|
},
|
||||||
reorderQueue({ it.download.chapter.date_upload }, false)
|
)
|
||||||
onExpanded(false)
|
DropdownMenuItem(
|
||||||
},
|
text = { Text(text = stringResource(R.string.action_order_by_chapter_number)) },
|
||||||
)
|
children = {
|
||||||
},
|
DropdownMenuItem(
|
||||||
)
|
text = { Text(text = stringResource(R.string.action_asc)) },
|
||||||
DropdownMenuItem(
|
onClick = {
|
||||||
text = { Text(text = stringResource(R.string.action_order_by_chapter_number)) },
|
reorderQueue(
|
||||||
children = {
|
{ it.download.chapter.chapter_number },
|
||||||
DropdownMenuItem(
|
false,
|
||||||
text = { Text(text = stringResource(R.string.action_asc)) },
|
)
|
||||||
onClick = {
|
closeMenu()
|
||||||
reorderQueue({ it.download.chapter.chapter_number }, false)
|
},
|
||||||
onExpanded(false)
|
)
|
||||||
},
|
DropdownMenuItem(
|
||||||
)
|
text = { Text(text = stringResource(R.string.action_desc)) },
|
||||||
DropdownMenuItem(
|
onClick = {
|
||||||
text = { Text(text = stringResource(R.string.action_desc)) },
|
reorderQueue(
|
||||||
onClick = {
|
{ it.download.chapter.chapter_number },
|
||||||
reorderQueue({ it.download.chapter.chapter_number }, true)
|
true,
|
||||||
onExpanded(false)
|
)
|
||||||
},
|
closeMenu()
|
||||||
)
|
},
|
||||||
},
|
)
|
||||||
)
|
},
|
||||||
},
|
)
|
||||||
)
|
},
|
||||||
DropdownMenuItem(
|
)
|
||||||
text = { Text(text = stringResource(R.string.action_cancel_all)) },
|
DropdownMenuItem(
|
||||||
onClick = {
|
text = { Text(text = stringResource(R.string.action_cancel_all)) },
|
||||||
presenter.clearQueue(context)
|
onClick = {
|
||||||
onExpanded(false)
|
presenter.clearQueue(context)
|
||||||
},
|
closeMenu()
|
||||||
)
|
},
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -15,6 +15,8 @@ import eu.kanade.domain.manga.model.toDbManga
|
|||||||
import eu.kanade.presentation.components.ChangeCategoryDialog
|
import eu.kanade.presentation.components.ChangeCategoryDialog
|
||||||
import eu.kanade.presentation.components.DeleteLibraryMangaDialog
|
import eu.kanade.presentation.components.DeleteLibraryMangaDialog
|
||||||
import eu.kanade.presentation.library.LibraryScreen
|
import eu.kanade.presentation.library.LibraryScreen
|
||||||
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
|
import eu.kanade.presentation.manga.components.DownloadCustomAmountDialog
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
|
import eu.kanade.tachiyomi.ui.base.controller.FullComposeController
|
||||||
@ -43,6 +45,8 @@ class LibraryController(
|
|||||||
@Composable
|
@Composable
|
||||||
override fun ComposeContent() {
|
override fun ComposeContent() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val getMangaForCategory = presenter.getMangaForCategory(page = presenter.activeCategory)
|
||||||
|
|
||||||
LibraryScreen(
|
LibraryScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
onMangaClicked = ::openManga,
|
onMangaClicked = ::openManga,
|
||||||
@ -52,7 +56,7 @@ class LibraryController(
|
|||||||
onChangeCategoryClicked = ::showMangaCategoriesDialog,
|
onChangeCategoryClicked = ::showMangaCategoriesDialog,
|
||||||
onMarkAsReadClicked = { markReadStatus(true) },
|
onMarkAsReadClicked = { markReadStatus(true) },
|
||||||
onMarkAsUnreadClicked = { markReadStatus(false) },
|
onMarkAsUnreadClicked = { markReadStatus(false) },
|
||||||
onDownloadClicked = ::downloadUnreadChapters,
|
onDownloadClicked = ::runDownloadChapterAction,
|
||||||
onDeleteClicked = ::showDeleteMangaDialog,
|
onDeleteClicked = ::showDeleteMangaDialog,
|
||||||
onClickFilter = ::showSettingsSheet,
|
onClickFilter = ::showSettingsSheet,
|
||||||
onClickRefresh = {
|
onClickRefresh = {
|
||||||
@ -60,6 +64,14 @@ class LibraryController(
|
|||||||
context.toast(if (started) R.string.updating_category else R.string.update_already_running)
|
context.toast(if (started) R.string.updating_category else R.string.update_already_running)
|
||||||
started
|
started
|
||||||
},
|
},
|
||||||
|
onClickOpenRandomManga = {
|
||||||
|
val items = getMangaForCategory.map { it.libraryManga.manga.id }
|
||||||
|
if (getMangaForCategory.isNotEmpty()) {
|
||||||
|
openManga(items.random())
|
||||||
|
} else {
|
||||||
|
context.toast(R.string.information_no_entries_found)
|
||||||
|
}
|
||||||
|
},
|
||||||
onClickInvertSelection = { presenter.invertSelection(presenter.activeCategory) },
|
onClickInvertSelection = { presenter.invertSelection(presenter.activeCategory) },
|
||||||
onClickSelectAll = { presenter.selectAll(presenter.activeCategory) },
|
onClickSelectAll = { presenter.selectAll(presenter.activeCategory) },
|
||||||
onClickUnselectAll = ::clearSelection,
|
onClickUnselectAll = ::clearSelection,
|
||||||
@ -91,6 +103,16 @@ class LibraryController(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
is LibraryPresenter.Dialog.DownloadCustomAmount -> {
|
||||||
|
DownloadCustomAmountDialog(
|
||||||
|
maxAmount = dialog.max,
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
onConfirm = { amount ->
|
||||||
|
presenter.downloadUnreadChapters(dialog.manga, amount)
|
||||||
|
presenter.clearSelection()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
null -> {}
|
null -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +230,22 @@ class LibraryController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadUnreadChapters() {
|
private fun runDownloadChapterAction(action: DownloadAction) {
|
||||||
val mangaList = presenter.selection.toList()
|
val mangas = presenter.selection.map { it.manga }.toList()
|
||||||
presenter.downloadUnreadChapters(mangaList.map { it.manga })
|
when (action) {
|
||||||
|
DownloadAction.NEXT_1_CHAPTER -> presenter.downloadUnreadChapters(mangas, 1)
|
||||||
|
DownloadAction.NEXT_5_CHAPTERS -> presenter.downloadUnreadChapters(mangas, 5)
|
||||||
|
DownloadAction.NEXT_10_CHAPTERS -> presenter.downloadUnreadChapters(mangas, 10)
|
||||||
|
DownloadAction.UNREAD_CHAPTERS -> presenter.downloadUnreadChapters(mangas, null)
|
||||||
|
DownloadAction.CUSTOM -> {
|
||||||
|
presenter.dialog = LibraryPresenter.Dialog.DownloadCustomAmount(
|
||||||
|
mangas,
|
||||||
|
presenter.selection.maxOf { it.unreadCount }.toInt(),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
presenter.clearSelection()
|
presenter.clearSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,9 +17,9 @@ import eu.kanade.domain.base.BasePreferences
|
|||||||
import eu.kanade.domain.category.interactor.GetCategories
|
import eu.kanade.domain.category.interactor.GetCategories
|
||||||
import eu.kanade.domain.category.interactor.SetMangaCategories
|
import eu.kanade.domain.category.interactor.SetMangaCategories
|
||||||
import eu.kanade.domain.category.model.Category
|
import eu.kanade.domain.category.model.Category
|
||||||
import eu.kanade.domain.chapter.interactor.GetChapterByMangaId
|
|
||||||
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
import eu.kanade.domain.chapter.interactor.SetReadStatus
|
||||||
import eu.kanade.domain.chapter.model.toDbChapter
|
import eu.kanade.domain.chapter.model.toDbChapter
|
||||||
|
import eu.kanade.domain.history.interactor.GetNextUnreadChapters
|
||||||
import eu.kanade.domain.library.model.LibraryManga
|
import eu.kanade.domain.library.model.LibraryManga
|
||||||
import eu.kanade.domain.library.model.LibrarySort
|
import eu.kanade.domain.library.model.LibrarySort
|
||||||
import eu.kanade.domain.library.model.sort
|
import eu.kanade.domain.library.model.sort
|
||||||
@ -78,7 +78,7 @@ class LibraryPresenter(
|
|||||||
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
||||||
private val getTracksPerManga: GetTracksPerManga = Injekt.get(),
|
private val getTracksPerManga: GetTracksPerManga = Injekt.get(),
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories = Injekt.get(),
|
||||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
private val getNextUnreadChapters: GetNextUnreadChapters = Injekt.get(),
|
||||||
private val setReadStatus: SetReadStatus = Injekt.get(),
|
private val setReadStatus: SetReadStatus = Injekt.get(),
|
||||||
private val updateManga: UpdateManga = Injekt.get(),
|
private val updateManga: UpdateManga = Injekt.get(),
|
||||||
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
private val setMangaCategories: SetMangaCategories = Injekt.get(),
|
||||||
@ -402,18 +402,27 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queues all unread chapters from the given list of manga.
|
* Queues the amount specified of unread chapters from the list of mangas given.
|
||||||
*
|
*
|
||||||
* @param mangas the list of manga.
|
* @param mangas the list of manga.
|
||||||
|
* @param amount the amount to queue or null to queue all
|
||||||
*/
|
*/
|
||||||
fun downloadUnreadChapters(mangas: List<Manga>) {
|
fun downloadUnreadChapters(mangas: List<Manga>, amount: Int?) {
|
||||||
presenterScope.launchNonCancellable {
|
presenterScope.launchNonCancellable {
|
||||||
mangas.forEach { manga ->
|
mangas.forEach { manga ->
|
||||||
val chapters = getChapterByMangaId.await(manga.id)
|
val chapters = getNextUnreadChapters.await(manga.id)
|
||||||
.filter { !it.read }
|
.filterNot { chapter ->
|
||||||
.map { it.toDbChapter() }
|
downloadManager.queue.any { chapter.id == it.chapter.id } ||
|
||||||
|
downloadManager.isChapterDownloaded(
|
||||||
|
chapter.name,
|
||||||
|
chapter.scanlator,
|
||||||
|
manga.title,
|
||||||
|
manga.source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.let { if (amount != null) it.take(amount) else it }
|
||||||
|
|
||||||
downloadManager.downloadChapters(manga, chapters)
|
downloadManager.downloadChapters(manga, chapters.map { it.toDbChapter() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -526,7 +535,7 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getMangaForCategory(page: Int): List<LibraryItem> {
|
fun getMangaForCategory(page: Int): List<LibraryItem> {
|
||||||
val unfiltered = remember(categories, loadedManga) {
|
val unfiltered = remember(categories, loadedManga, page) {
|
||||||
val categoryId = categories.getOrNull(page)?.id ?: -1
|
val categoryId = categories.getOrNull(page)?.id ?: -1
|
||||||
loadedManga[categoryId] ?: emptyList()
|
loadedManga[categoryId] ?: emptyList()
|
||||||
}
|
}
|
||||||
@ -604,5 +613,6 @@ class LibraryPresenter(
|
|||||||
sealed class Dialog {
|
sealed class Dialog {
|
||||||
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||||
data class DeleteManga(val manga: List<Manga>) : Dialog()
|
data class DeleteManga(val manga: List<Manga>) : Dialog()
|
||||||
|
data class DownloadCustomAmount(val manga: List<Manga>, val max: Int) : Dialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.ui.base.controller.pushController
|
|||||||
import eu.kanade.tachiyomi.ui.category.CategoryController
|
import eu.kanade.tachiyomi.ui.category.CategoryController
|
||||||
import eu.kanade.tachiyomi.ui.download.DownloadController
|
import eu.kanade.tachiyomi.ui.download.DownloadController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
||||||
|
import eu.kanade.tachiyomi.util.system.isInstalledFromFDroid
|
||||||
|
|
||||||
class MoreController :
|
class MoreController :
|
||||||
FullComposeController<MorePresenter>(),
|
FullComposeController<MorePresenter>(),
|
||||||
@ -19,6 +20,7 @@ class MoreController :
|
|||||||
override fun ComposeContent() {
|
override fun ComposeContent() {
|
||||||
MoreScreen(
|
MoreScreen(
|
||||||
presenter = presenter,
|
presenter = presenter,
|
||||||
|
isFDroid = activity?.isInstalledFromFDroid() ?: false,
|
||||||
onClickDownloadQueue = { router.pushController(DownloadController()) },
|
onClickDownloadQueue = { router.pushController(DownloadController()) },
|
||||||
onClickCategories = { router.pushController(CategoryController()) },
|
onClickCategories = { router.pushController(CategoryController()) },
|
||||||
onClickBackupAndRestore = { router.pushController(SettingsMainController.toBackupScreen()) },
|
onClickBackupAndRestore = { router.pushController(SettingsMainController.toBackupScreen()) },
|
||||||
|
@ -11,6 +11,7 @@ import eu.kanade.domain.chapter.interactor.UpdateChapter
|
|||||||
import eu.kanade.domain.chapter.model.ChapterUpdate
|
import eu.kanade.domain.chapter.model.ChapterUpdate
|
||||||
import eu.kanade.domain.chapter.model.toDbChapter
|
import eu.kanade.domain.chapter.model.toDbChapter
|
||||||
import eu.kanade.domain.download.service.DownloadPreferences
|
import eu.kanade.domain.download.service.DownloadPreferences
|
||||||
|
import eu.kanade.domain.history.interactor.GetNextUnreadChapters
|
||||||
import eu.kanade.domain.history.interactor.UpsertHistory
|
import eu.kanade.domain.history.interactor.UpsertHistory
|
||||||
import eu.kanade.domain.history.model.HistoryUpdate
|
import eu.kanade.domain.history.model.HistoryUpdate
|
||||||
import eu.kanade.domain.manga.interactor.GetManga
|
import eu.kanade.domain.manga.interactor.GetManga
|
||||||
@ -22,7 +23,6 @@ import eu.kanade.domain.track.interactor.InsertTrack
|
|||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
import eu.kanade.domain.track.service.TrackPreferences
|
import eu.kanade.domain.track.service.TrackPreferences
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
import eu.kanade.tachiyomi.data.database.models.toDomainManga
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||||
@ -59,7 +59,6 @@ import eu.kanade.tachiyomi.util.storage.DiskUtil
|
|||||||
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
||||||
import eu.kanade.tachiyomi.util.system.isOnline
|
import eu.kanade.tachiyomi.util.system.isOnline
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import eu.kanade.tachiyomi.util.system.toInt
|
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@ -74,7 +73,6 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import eu.kanade.domain.manga.model.Manga as DomainManga
|
import eu.kanade.domain.manga.model.Manga as DomainManga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter as DbChapter
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter used by the activity to perform background operations.
|
* Presenter used by the activity to perform background operations.
|
||||||
@ -90,6 +88,7 @@ class ReaderPresenter(
|
|||||||
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
|
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
|
||||||
private val getManga: GetManga = Injekt.get(),
|
private val getManga: GetManga = Injekt.get(),
|
||||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||||
|
private val getNextUnreadChapters: GetNextUnreadChapters = Injekt.get(),
|
||||||
private val getTracks: GetTracks = Injekt.get(),
|
private val getTracks: GetTracks = Injekt.get(),
|
||||||
private val insertTrack: InsertTrack = Injekt.get(),
|
private val insertTrack: InsertTrack = Injekt.get(),
|
||||||
private val upsertHistory: UpsertHistory = Injekt.get(),
|
private val upsertHistory: UpsertHistory = Injekt.get(),
|
||||||
@ -393,7 +392,13 @@ class ReaderPresenter(
|
|||||||
if (chapter.pageLoader is HttpPageLoader) {
|
if (chapter.pageLoader is HttpPageLoader) {
|
||||||
val manga = manga ?: return
|
val manga = manga ?: return
|
||||||
val dbChapter = chapter.chapter
|
val dbChapter = chapter.chapter
|
||||||
val isDownloaded = downloadManager.isChapterDownloaded(dbChapter.name, dbChapter.scanlator, manga.title, manga.source, skipCache = true)
|
val isDownloaded = downloadManager.isChapterDownloaded(
|
||||||
|
dbChapter.name,
|
||||||
|
dbChapter.scanlator,
|
||||||
|
manga.title,
|
||||||
|
manga.source,
|
||||||
|
skipCache = true,
|
||||||
|
)
|
||||||
if (isDownloaded) {
|
if (isDownloaded) {
|
||||||
chapter.state = ReaderChapter.State.Wait
|
chapter.state = ReaderChapter.State.Wait
|
||||||
}
|
}
|
||||||
@ -406,7 +411,6 @@ class ReaderPresenter(
|
|||||||
logcat { "Preloading ${chapter.chapter.url}" }
|
logcat { "Preloading ${chapter.chapter.url}" }
|
||||||
|
|
||||||
val loader = loader ?: return
|
val loader = loader ?: return
|
||||||
|
|
||||||
loader.loadChapter(chapter)
|
loader.loadChapter(chapter)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
// Update current chapters whenever a chapter is preloaded
|
// Update current chapters whenever a chapter is preloaded
|
||||||
@ -447,7 +451,7 @@ class ReaderPresenter(
|
|||||||
loadNewChapter(selectedChapter)
|
loadNewChapter(selectedChapter)
|
||||||
}
|
}
|
||||||
val pages = page.chapter.pages ?: return
|
val pages = page.chapter.pages ?: return
|
||||||
val inDownloadRange = page.number.toDouble() / pages.size > 0.2
|
val inDownloadRange = page.number.toDouble() / pages.size > 0.25
|
||||||
if (inDownloadRange) {
|
if (inDownloadRange) {
|
||||||
downloadNextChapters()
|
downloadNextChapters()
|
||||||
}
|
}
|
||||||
@ -455,45 +459,31 @@ class ReaderPresenter(
|
|||||||
|
|
||||||
private fun downloadNextChapters() {
|
private fun downloadNextChapters() {
|
||||||
val manga = manga ?: return
|
val manga = manga ?: return
|
||||||
|
val amount = downloadPreferences.autoDownloadWhileReading().get()
|
||||||
|
if (amount == 0 || !manga.favorite) return
|
||||||
|
|
||||||
|
// Only download ahead if current + next chapter is already downloaded too to avoid jank
|
||||||
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
||||||
val nextChapter = viewerChaptersRelay.value?.nextChapter?.chapter ?: return
|
val nextChapter = viewerChaptersRelay.value?.nextChapter?.chapter ?: return
|
||||||
val chaptersNumberToDownload = downloadPreferences.autoDownloadWhileReading().get()
|
|
||||||
if (chaptersNumberToDownload == 0 || !manga.favorite) return
|
presenterScope.launchIO {
|
||||||
val isNextChapterDownloadedOrQueued = downloadManager.isChapterDownloaded(
|
val isNextChapterDownloaded = downloadManager.isChapterDownloaded(
|
||||||
nextChapter.name,
|
nextChapter.name,
|
||||||
nextChapter.scanlator,
|
nextChapter.scanlator,
|
||||||
manga.title,
|
manga.title,
|
||||||
manga.source,
|
manga.source,
|
||||||
skipCache = true,
|
)
|
||||||
) || downloadManager.getChapterDownloadOrNull(nextChapter) != null
|
if (!isNextChapterDownloaded) return@launchIO
|
||||||
if (isNextChapterDownloadedOrQueued) {
|
|
||||||
downloadAutoNextChapters(chaptersNumberToDownload, nextChapter.id, nextChapter.read)
|
val chaptersToDownload = getNextUnreadChapters.await(manga.id!!, nextChapter.id!!)
|
||||||
|
.take(amount)
|
||||||
|
downloadManager.downloadChapters(
|
||||||
|
manga.toDomainManga()!!,
|
||||||
|
chaptersToDownload.map { it.toDbChapter() },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadAutoNextChapters(choice: Int, nextChapterId: Long?, isNextChapterRead: Boolean) {
|
|
||||||
val chaptersToDownload = getNextUnreadChaptersSorted(nextChapterId).take(choice - 1 + isNextChapterRead.toInt())
|
|
||||||
if (chaptersToDownload.isNotEmpty()) {
|
|
||||||
downloadChapters(chaptersToDownload)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getNextUnreadChaptersSorted(nextChapterId: Long?): List<DbChapter> {
|
|
||||||
return chapterList.map { it.chapter.toDomainChapter()!! }
|
|
||||||
.filter { !it.read || it.id == nextChapterId }
|
|
||||||
.sortedWith(getChapterSort(manga?.toDomainManga()!!, false))
|
|
||||||
.map { it.toDbChapter() }
|
|
||||||
.takeLastWhile { it.id != nextChapterId }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloads the given list of chapters with the manager.
|
|
||||||
* @param chapters the list of chapters to download.
|
|
||||||
*/
|
|
||||||
private fun downloadChapters(chapters: List<DbChapter>) {
|
|
||||||
downloadManager.downloadChapters(manga?.toDomainManga()!!, chapters)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes [currentChapter] from download queue
|
* Removes [currentChapter] from download queue
|
||||||
* if setting is enabled and [currentChapter] is queued for download
|
* if setting is enabled and [currentChapter] is queued for download
|
||||||
|
@ -9,10 +9,10 @@ enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val str
|
|||||||
DEFAULT(0, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000),
|
DEFAULT(0, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.label_default, R.drawable.ic_screen_rotation_24dp, 0x00000000),
|
||||||
FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008),
|
FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008),
|
||||||
PORTRAIT(2, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010),
|
PORTRAIT(2, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010),
|
||||||
REVERSE_PORTRAIT(6, ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030),
|
|
||||||
LANDSCAPE(3, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018),
|
LANDSCAPE(3, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018),
|
||||||
LOCKED_PORTRAIT(4, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020),
|
LOCKED_PORTRAIT(4, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020),
|
||||||
LOCKED_LANDSCAPE(5, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028),
|
LOCKED_LANDSCAPE(5, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028),
|
||||||
|
REVERSE_PORTRAIT(6, ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, R.string.rotation_reverse_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000030),
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -11,7 +11,7 @@ import eu.kanade.domain.base.BasePreferences
|
|||||||
import eu.kanade.domain.chapter.model.Chapter
|
import eu.kanade.domain.chapter.model.Chapter
|
||||||
import eu.kanade.domain.history.interactor.DeleteAllHistory
|
import eu.kanade.domain.history.interactor.DeleteAllHistory
|
||||||
import eu.kanade.domain.history.interactor.GetHistory
|
import eu.kanade.domain.history.interactor.GetHistory
|
||||||
import eu.kanade.domain.history.interactor.GetNextChapter
|
import eu.kanade.domain.history.interactor.GetNextUnreadChapters
|
||||||
import eu.kanade.domain.history.interactor.RemoveHistoryById
|
import eu.kanade.domain.history.interactor.RemoveHistoryById
|
||||||
import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId
|
import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId
|
||||||
import eu.kanade.domain.history.model.HistoryWithRelations
|
import eu.kanade.domain.history.model.HistoryWithRelations
|
||||||
@ -37,7 +37,7 @@ import java.util.Date
|
|||||||
class HistoryPresenter(
|
class HistoryPresenter(
|
||||||
private val state: HistoryStateImpl = HistoryState() as HistoryStateImpl,
|
private val state: HistoryStateImpl = HistoryState() as HistoryStateImpl,
|
||||||
private val getHistory: GetHistory = Injekt.get(),
|
private val getHistory: GetHistory = Injekt.get(),
|
||||||
private val getNextChapter: GetNextChapter = Injekt.get(),
|
private val getNextUnreadChapters: GetNextUnreadChapters = Injekt.get(),
|
||||||
private val deleteAllHistory: DeleteAllHistory = Injekt.get(),
|
private val deleteAllHistory: DeleteAllHistory = Injekt.get(),
|
||||||
private val removeHistoryById: RemoveHistoryById = Injekt.get(),
|
private val removeHistoryById: RemoveHistoryById = Injekt.get(),
|
||||||
private val removeHistoryByMangaId: RemoveHistoryByMangaId = Injekt.get(),
|
private val removeHistoryByMangaId: RemoveHistoryByMangaId = Injekt.get(),
|
||||||
@ -94,7 +94,7 @@ class HistoryPresenter(
|
|||||||
|
|
||||||
fun getNextChapterForManga(mangaId: Long, chapterId: Long) {
|
fun getNextChapterForManga(mangaId: Long, chapterId: Long) {
|
||||||
presenterScope.launchIO {
|
presenterScope.launchIO {
|
||||||
val chapter = getNextChapter.await(mangaId, chapterId)
|
val chapter = getNextUnreadChapters.await(mangaId, chapterId).firstOrNull()
|
||||||
_events.send(if (chapter != null) Event.OpenChapter(chapter) else Event.NoNextChapterFound)
|
_events.send(if (chapter != null) Event.OpenChapter(chapter) else Event.NoNextChapterFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ class HistoryPresenter(
|
|||||||
|
|
||||||
fun resumeLastChapterRead() {
|
fun resumeLastChapterRead() {
|
||||||
presenterScope.launchIO {
|
presenterScope.launchIO {
|
||||||
val chapter = getNextChapter.await()
|
val chapter = getNextUnreadChapters.await()
|
||||||
_events.send(if (chapter != null) Event.OpenChapter(chapter) else Event.NoNextChapterFound)
|
_events.send(if (chapter != null) Event.OpenChapter(chapter) else Event.NoNextChapterFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,14 @@ import eu.kanade.tachiyomi.util.lang.launchNonCancellable
|
|||||||
import eu.kanade.tachiyomi.util.lang.withUIContext
|
import eu.kanade.tachiyomi.util.lang.withUIContext
|
||||||
import eu.kanade.tachiyomi.util.system.logcat
|
import eu.kanade.tachiyomi.util.system.logcat
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@ -87,11 +88,11 @@ class UpdatesPresenter(
|
|||||||
getUpdates.subscribe(calendar).distinctUntilChanged(),
|
getUpdates.subscribe(calendar).distinctUntilChanged(),
|
||||||
downloadCache.changes,
|
downloadCache.changes,
|
||||||
) { updates, _ -> updates }
|
) { updates, _ -> updates }
|
||||||
|
.onStart { delay(500) } // Defer to avoid crashing on initial render
|
||||||
.catch {
|
.catch {
|
||||||
logcat(LogPriority.ERROR, it)
|
logcat(LogPriority.ERROR, it)
|
||||||
_events.send(Event.InternalError)
|
_events.send(Event.InternalError)
|
||||||
}
|
}
|
||||||
.stateIn(presenterScope)
|
|
||||||
.collectLatest { updates ->
|
.collectLatest { updates ->
|
||||||
state.items = updates.toUpdateItems()
|
state.items = updates.toUpdateItems()
|
||||||
state.isLoading = false
|
state.isLoading = false
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
package eu.kanade.tachiyomi.util.system
|
package eu.kanade.tachiyomi.util.system
|
||||||
|
|
||||||
fun Boolean.toInt() = if (this) 1 else 0
|
|
||||||
|
|
||||||
fun Boolean.toLong() = if (this) 1L else 0L
|
fun Boolean.toLong() = if (this) 1L else 0L
|
||||||
|
@ -39,6 +39,7 @@ import androidx.core.net.toUri
|
|||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.domain.ui.UiPreferences
|
import eu.kanade.domain.ui.UiPreferences
|
||||||
import eu.kanade.domain.ui.model.TabletUiMode
|
import eu.kanade.domain.ui.model.TabletUiMode
|
||||||
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate
|
import eu.kanade.tachiyomi.ui.base.delegate.ThemingDelegate
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
@ -393,8 +394,8 @@ fun Context.isPackageInstalled(packageName: String): Boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getInstallerPackageName(): String? {
|
fun Context.isInstalledFromFDroid(): Boolean {
|
||||||
return try {
|
val installerPackageName = try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
packageManager.getInstallSourceInfo(packageName).installingPackageName
|
packageManager.getInstallSourceInfo(packageName).installingPackageName
|
||||||
} else {
|
} else {
|
||||||
@ -404,6 +405,10 @@ fun Context.getInstallerPackageName(): String? {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return installerPackageName == "org.fdroid.fdroid" ||
|
||||||
|
// F-Droid builds typically disable the updater
|
||||||
|
(!BuildConfig.INCLUDE_UPDATER && !isDevFlavor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.getApplicationIcon(pkgName: String): Drawable? {
|
fun Context.getApplicationIcon(pkgName: String): Drawable? {
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
<item>@string/rotation_landscape</item>
|
<item>@string/rotation_landscape</item>
|
||||||
<item>@string/rotation_force_portrait</item>
|
<item>@string/rotation_force_portrait</item>
|
||||||
<item>@string/rotation_force_landscape</item>
|
<item>@string/rotation_force_landscape</item>
|
||||||
|
<item>@string/rotation_reverse_portrait</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="color_filter_modes">
|
<string-array name="color_filter_modes">
|
||||||
|
@ -32,10 +32,12 @@ SELECT *
|
|||||||
FROM mangas
|
FROM mangas
|
||||||
WHERE _id = :id;
|
WHERE _id = :id;
|
||||||
|
|
||||||
|
-- TODO: this should ideally never really have more than 1 result
|
||||||
getMangaByUrlAndSource:
|
getMangaByUrlAndSource:
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM mangas
|
FROM mangas
|
||||||
WHERE url = :url AND source = :source;
|
WHERE url = :url AND source = :source
|
||||||
|
LIMIT 1;
|
||||||
|
|
||||||
getFavorites:
|
getFavorites:
|
||||||
SELECT *
|
SELECT *
|
||||||
|
@ -19,6 +19,4 @@ material-icons = { module = "androidx.compose.material:material-icons-extended"
|
|||||||
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
|
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" }
|
||||||
accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanist" }
|
accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanist" }
|
||||||
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
|
accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" }
|
||||||
accompanist-pager-core = { module = "com.google.accompanist:accompanist-pager", version.ref = "accompanist" }
|
|
||||||
accompanist-pager-indicators = { module = "com.google.accompanist:accompanist-pager-indicators", version.ref = "accompanist" }
|
|
||||||
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" }
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
[versions]
|
[versions]
|
||||||
kotlin_version = "1.7.20"
|
kotlin_version = "1.7.20"
|
||||||
coroutines_version = "1.6.4"
|
serialization_version = "1.4.0"
|
||||||
serialization_version = "1.4.1"
|
|
||||||
xml_serialization_version = "0.84.3"
|
xml_serialization_version = "0.84.3"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" }
|
reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin_version" }
|
||||||
gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" }
|
gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin_version" }
|
||||||
|
|
||||||
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines_version" }
|
coroutines-bom = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-bom", version = "1.6.4" }
|
||||||
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "coroutines_version" }
|
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core" }
|
||||||
|
coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android" }
|
||||||
|
|
||||||
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_version" }
|
# TODO: 1.4.1 introduces an issue with cached serializers; see https://github.com/Kotlin/kotlinx.serialization/issues/2065
|
||||||
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization_version" }
|
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version = "1.4.0" }
|
||||||
|
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version = "1.4.0" }
|
||||||
serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" }
|
serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" }
|
||||||
serialization-gradle = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version" }
|
serialization-gradle = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version" }
|
||||||
serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core-android", version.ref = "xml_serialization_version" }
|
serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core-android", version.ref = "xml_serialization_version" }
|
||||||
|
@ -8,7 +8,7 @@ flowbinding_version = "1.2.0"
|
|||||||
shizuku_version = "12.2.0"
|
shizuku_version = "12.2.0"
|
||||||
sqldelight = "1.5.4"
|
sqldelight = "1.5.4"
|
||||||
leakcanary = "2.9.1"
|
leakcanary = "2.9.1"
|
||||||
voyager = "1.0.0-rc05"
|
voyager = "1.0.0-rc06"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2"
|
android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2"
|
||||||
|
@ -661,7 +661,7 @@
|
|||||||
<string name="notification_update_error">%1$d আপডেট(গুলি) ব্যর্থ হয়েছে</string>
|
<string name="notification_update_error">%1$d আপডেট(গুলি) ব্যর্থ হয়েছে</string>
|
||||||
<string name="publishing_finished">সম্পূর্ণ প্রকাশিত</string>
|
<string name="publishing_finished">সম্পূর্ণ প্রকাশিত</string>
|
||||||
<string name="action_filter_started">শুরু করা হয়েছে</string>
|
<string name="action_filter_started">শুরু করা হয়েছে</string>
|
||||||
<string name="action_sort_last_manga_update">সর্বশেষ মাঙ্গা হালনাগাদ</string>
|
<string name="action_sort_last_manga_update">সর্বশেষ হালনাগাদ চেক</string>
|
||||||
<string name="delete_category_confirmation">আপনি কি \"%s\" বিভাগটি মুছে ফেলতে চান\?</string>
|
<string name="delete_category_confirmation">আপনি কি \"%s\" বিভাগটি মুছে ফেলতে চান\?</string>
|
||||||
<string name="appwidget_updates_description">সম্প্রতি আপনার হালনাগাদকৃত মাঙ্গা দেখুন</string>
|
<string name="appwidget_updates_description">সম্প্রতি আপনার হালনাগাদকৃত মাঙ্গা দেখুন</string>
|
||||||
<string name="are_you_sure">আপনি কি নিশ্চিত\?</string>
|
<string name="are_you_sure">আপনি কি নিশ্চিত\?</string>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="name">Nom</string>
|
<string name="name">Nom</string>
|
||||||
<string name="categories">Categories</string>
|
<string name="categories">Categories</string>
|
||||||
<string name="manga">Manga</string>
|
<string name="manga">Mangues</string>
|
||||||
<string name="chapters">Capítols</string>
|
<string name="chapters">Capítols</string>
|
||||||
<string name="track">En seguiment</string>
|
<string name="track">En seguiment</string>
|
||||||
<string name="history">Historial</string>
|
<string name="history">Historial</string>
|
||||||
@ -69,7 +69,7 @@
|
|||||||
<string name="pref_category_general">General</string>
|
<string name="pref_category_general">General</string>
|
||||||
<string name="pref_category_reader">Lector</string>
|
<string name="pref_category_reader">Lector</string>
|
||||||
<string name="pref_category_downloads">Baixades</string>
|
<string name="pref_category_downloads">Baixades</string>
|
||||||
<string name="pref_category_tracking">En seguiment</string>
|
<string name="pref_category_tracking">Seguiment</string>
|
||||||
<string name="pref_category_advanced">Avançat</string>
|
<string name="pref_category_advanced">Avançat</string>
|
||||||
<string name="pref_category_about">Quant a</string>
|
<string name="pref_category_about">Quant a</string>
|
||||||
<string name="pref_library_columns">Elements per fila</string>
|
<string name="pref_library_columns">Elements per fila</string>
|
||||||
@ -85,7 +85,7 @@
|
|||||||
<string name="all">Tot</string>
|
<string name="all">Tot</string>
|
||||||
<string name="pref_library_update_restriction">Restriccions del dispositiu per a les actualitzacions automàtiques</string>
|
<string name="pref_library_update_restriction">Restriccions del dispositiu per a les actualitzacions automàtiques</string>
|
||||||
<string name="charging">Quan s\'estigui carregant</string>
|
<string name="charging">Quan s\'estigui carregant</string>
|
||||||
<string name="pref_update_only_non_completed">Amb l\'estat «Completada»</string>
|
<string name="pref_update_only_non_completed">Amb l\'estat «Completat»</string>
|
||||||
<string name="pref_auto_update_manga_sync">Actualitza el progrés després de llegir</string>
|
<string name="pref_auto_update_manga_sync">Actualitza el progrés després de llegir</string>
|
||||||
<string name="default_category">Categoria per defecte</string>
|
<string name="default_category">Categoria per defecte</string>
|
||||||
<string name="default_category_summary">Demana-ho sempre</string>
|
<string name="default_category_summary">Demana-ho sempre</string>
|
||||||
@ -94,7 +94,7 @@
|
|||||||
<string name="ext_pending">Pendent</string>
|
<string name="ext_pending">Pendent</string>
|
||||||
<string name="ext_downloading">S\'està baixant</string>
|
<string name="ext_downloading">S\'està baixant</string>
|
||||||
<string name="ext_installing">S\'està instal·lant</string>
|
<string name="ext_installing">S\'està instal·lant</string>
|
||||||
<string name="ext_installed">Instal·lada</string>
|
<string name="ext_installed">Instal·lades</string>
|
||||||
<string name="ext_trust">Confia-hi</string>
|
<string name="ext_trust">Confia-hi</string>
|
||||||
<string name="ext_untrusted">No és de confiança</string>
|
<string name="ext_untrusted">No és de confiança</string>
|
||||||
<string name="ext_uninstall">Desinstal·la</string>
|
<string name="ext_uninstall">Desinstal·la</string>
|
||||||
@ -179,8 +179,8 @@
|
|||||||
<string name="pref_clear_cookies">Esborra les galetes</string>
|
<string name="pref_clear_cookies">Esborra les galetes</string>
|
||||||
<string name="cookies_cleared">S\'han esborrat les galetes</string>
|
<string name="cookies_cleared">S\'han esborrat les galetes</string>
|
||||||
<string name="pref_clear_database">Buida la base de dades</string>
|
<string name="pref_clear_database">Buida la base de dades</string>
|
||||||
<string name="pref_clear_database_summary">Suprimeix l\'historial del manga que no sigui a la biblioteca</string>
|
<string name="pref_clear_database_summary">Suprimeix l\'historial dels elements que no siguin a la biblioteca</string>
|
||||||
<string name="clear_database_confirmation">N\'esteu segur\? Es perdrà el progrés i els capítols llegits del manga que no sigui a la biblioteca</string>
|
<string name="clear_database_confirmation">N\'esteu segur\? Es perdrà el progrés i els capítols llegits dels elements que no siguin a la biblioteca</string>
|
||||||
<string name="clear_database_completed">S\'han suprimit les entrades</string>
|
<string name="clear_database_completed">S\'han suprimit les entrades</string>
|
||||||
<string name="pref_refresh_library_tracking">Refresca el seguiment</string>
|
<string name="pref_refresh_library_tracking">Refresca el seguiment</string>
|
||||||
<string name="pref_refresh_library_tracking_summary">Actualitza l\'estat, la puntuació i el darrer capítol llegit dels serveis de seguiment</string>
|
<string name="pref_refresh_library_tracking_summary">Actualitza l\'estat, la puntuació i el darrer capítol llegit dels serveis de seguiment</string>
|
||||||
@ -244,8 +244,8 @@
|
|||||||
<string name="error_category_exists">Ja hi ha una categoria amb aquest nom!</string>
|
<string name="error_category_exists">Ja hi ha una categoria amb aquest nom!</string>
|
||||||
<string name="snack_categories_deleted">S\'han suprimit les categories</string>
|
<string name="snack_categories_deleted">S\'han suprimit les categories</string>
|
||||||
<string name="dialog_with_checkbox_remove_description">S\'eliminarà la data de lectura d\'aquest capítol. N\'esteu segur\?</string>
|
<string name="dialog_with_checkbox_remove_description">S\'eliminarà la data de lectura d\'aquest capítol. N\'esteu segur\?</string>
|
||||||
<string name="dialog_with_checkbox_reset">Reinicia tots els capítols d\'aquest manga</string>
|
<string name="dialog_with_checkbox_reset">Reinicia tots els capítols d\'aquest element</string>
|
||||||
<string name="snack_add_to_library">Voleu afegir el manga a la biblioteca\?</string>
|
<string name="snack_add_to_library">Voleu afegir-lo a la biblioteca\?</string>
|
||||||
<string name="picture_saved">S\'ha desat la imatge</string>
|
<string name="picture_saved">S\'ha desat la imatge</string>
|
||||||
<string name="custom_filter">Filtre personalitzat</string>
|
<string name="custom_filter">Filtre personalitzat</string>
|
||||||
<string name="set_as_cover">Defineix com a portada</string>
|
<string name="set_as_cover">Defineix com a portada</string>
|
||||||
@ -268,14 +268,14 @@
|
|||||||
<string name="download_queue_error">No s\'han pogut baixar els capítols. Podeu tornar-ho a provar a la secció de baixades</string>
|
<string name="download_queue_error">No s\'han pogut baixar els capítols. Podeu tornar-ho a provar a la secció de baixades</string>
|
||||||
<string name="notification_new_chapters">S\'han trobat nous capítols</string>
|
<string name="notification_new_chapters">S\'han trobat nous capítols</string>
|
||||||
<string name="notification_cover_update_failed">No s\'ha pogut actualitzar la portada</string>
|
<string name="notification_cover_update_failed">No s\'ha pogut actualitzar la portada</string>
|
||||||
<string name="notification_first_add_to_library">Afegiu el manga a la vostra biblioteca abans de fer això</string>
|
<string name="notification_first_add_to_library">Afegiu l\'element a la vostra biblioteca abans de fer això</string>
|
||||||
<string name="file_select_cover">Seleccioneu la imatge de portada</string>
|
<string name="file_select_cover">Seleccioneu la imatge de portada</string>
|
||||||
<string name="file_select_backup">Seleccioneu el fitxer de còpia de seguretat</string>
|
<string name="file_select_backup">Seleccioneu el fitxer de còpia de seguretat</string>
|
||||||
<string name="update_check_confirm">Baixa</string>
|
<string name="update_check_confirm">Baixa</string>
|
||||||
<string name="update_check_no_new_updates">No hi ha cap nova actualització disponible</string>
|
<string name="update_check_no_new_updates">No hi ha cap nova actualització disponible</string>
|
||||||
<string name="update_check_look_for_updates">S\'estan cercant actualitzacions…</string>
|
<string name="update_check_look_for_updates">S\'estan cercant actualitzacions…</string>
|
||||||
<string name="update_check_notification_download_in_progress">S\'està baixant…</string>
|
<string name="update_check_notification_download_in_progress">S\'està baixant…</string>
|
||||||
<string name="update_check_notification_download_complete">Premeu per a instal·lar</string>
|
<string name="update_check_notification_download_complete">Premeu per a instal·lar l\'actualització</string>
|
||||||
<string name="update_check_notification_download_error">Error de baixada</string>
|
<string name="update_check_notification_download_error">Error de baixada</string>
|
||||||
<string name="update_check_notification_update_available">Nova versió disponible!</string>
|
<string name="update_check_notification_update_available">Nova versió disponible!</string>
|
||||||
<string name="information_no_downloads">No hi ha baixades</string>
|
<string name="information_no_downloads">No hi ha baixades</string>
|
||||||
@ -302,13 +302,13 @@
|
|||||||
<string name="filter_mode_darken">Crema / Enfosqueix</string>
|
<string name="filter_mode_darken">Crema / Enfosqueix</string>
|
||||||
<string name="label_help">Ajuda</string>
|
<string name="label_help">Ajuda</string>
|
||||||
<string name="no_results_found">No s\'ha trobat cap resultat</string>
|
<string name="no_results_found">No s\'ha trobat cap resultat</string>
|
||||||
<string name="migration_selection_prompt">Seleccioneu un origen del qual vulgueu migrar</string>
|
<string name="migration_selection_prompt">Seleccioneu una font a migrar</string>
|
||||||
<string name="action_webview_back">Endarrere</string>
|
<string name="action_webview_back">Endarrere</string>
|
||||||
<string name="action_webview_forward">Endavant</string>
|
<string name="action_webview_forward">Endavant</string>
|
||||||
<string name="action_webview_refresh">Actualitza</string>
|
<string name="action_webview_refresh">Actualitza</string>
|
||||||
<string name="pref_category_library">Biblioteca</string>
|
<string name="pref_category_library">Biblioteca</string>
|
||||||
<string name="ext_obsolete">Obsoleta</string>
|
<string name="ext_obsolete">Obsoleta</string>
|
||||||
<string name="obsolete_extension_message">Aquesta extensió ja no està disponible.</string>
|
<string name="obsolete_extension_message">Aquesta extensió ja no està disponible. És possible que no funcioni correctament i pot causar problemes a l\'aplicació. És recomanable que la desinstal·leu.</string>
|
||||||
<string name="pref_date_format">Format de data</string>
|
<string name="pref_date_format">Format de data</string>
|
||||||
<string name="pref_category_library_update">Actualització global</string>
|
<string name="pref_category_library_update">Actualització global</string>
|
||||||
<string name="logout_title">Voleu tancar la sessió a %1$s\?</string>
|
<string name="logout_title">Voleu tancar la sessió a %1$s\?</string>
|
||||||
@ -361,8 +361,8 @@
|
|||||||
<string name="email">Adreça electrònica</string>
|
<string name="email">Adreça electrònica</string>
|
||||||
<string name="pref_always_show_chapter_transition">Mostra sempre la transició de capítol</string>
|
<string name="pref_always_show_chapter_transition">Mostra sempre la transició de capítol</string>
|
||||||
<plurals name="notification_new_chapters_summary">
|
<plurals name="notification_new_chapters_summary">
|
||||||
<item quantity="one">Per a %d títol</item>
|
<item quantity="one">Per a %d element</item>
|
||||||
<item quantity="other">Per a %d títols</item>
|
<item quantity="other">Per a %d elements</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="action_menu">Menú</string>
|
<string name="action_menu">Menú</string>
|
||||||
<string name="action_reorganize_by">Reordena</string>
|
<string name="action_reorganize_by">Reordena</string>
|
||||||
@ -382,7 +382,7 @@
|
|||||||
<string name="pref_skip_filtered_chapters">Omet els capítols filtrats</string>
|
<string name="pref_skip_filtered_chapters">Omet els capítols filtrats</string>
|
||||||
<string name="label_sources">Fonts</string>
|
<string name="label_sources">Fonts</string>
|
||||||
<string name="action_select_inverse">Inverteix la selecció</string>
|
<string name="action_select_inverse">Inverteix la selecció</string>
|
||||||
<string name="pinned_sources">Fixat</string>
|
<string name="pinned_sources">Fixades</string>
|
||||||
<string name="action_pin">Fixa</string>
|
<string name="action_pin">Fixa</string>
|
||||||
<string name="add_tracking">Segueix</string>
|
<string name="add_tracking">Segueix</string>
|
||||||
<string name="webtoon_side_padding_25">25%</string>
|
<string name="webtoon_side_padding_25">25%</string>
|
||||||
@ -410,10 +410,10 @@
|
|||||||
<string name="restore_in_progress">Ja s\'està fent una restauració</string>
|
<string name="restore_in_progress">Ja s\'està fent una restauració</string>
|
||||||
<string name="backup_in_progress">Ja s\'està fent una còpia de seguretat</string>
|
<string name="backup_in_progress">Ja s\'està fent una còpia de seguretat</string>
|
||||||
<string name="local_source_help_guide">Guia de fonts locals</string>
|
<string name="local_source_help_guide">Guia de fonts locals</string>
|
||||||
<string name="last_used_source">Utilitzada per darrer cop</string>
|
<string name="last_used_source">Utilitzada per darrera vegada</string>
|
||||||
<string name="check_for_updates">Comprova si hi ha actualitzacions</string>
|
<string name="check_for_updates">Comprova si hi ha actualitzacions</string>
|
||||||
<string name="restore_duration">%02d min i %02d s</string>
|
<string name="restore_duration">%02d min i %02d s</string>
|
||||||
<string name="downloaded_only_summary">Filtra tot el manga de la vostra biblioteca</string>
|
<string name="downloaded_only_summary">Filtra tots els elements de la vostra biblioteca</string>
|
||||||
<plurals name="download_queue_summary">
|
<plurals name="download_queue_summary">
|
||||||
<item quantity="one">En resta %1$s</item>
|
<item quantity="one">En resta %1$s</item>
|
||||||
<item quantity="other">En resten %1$s</item>
|
<item quantity="other">En resten %1$s</item>
|
||||||
@ -433,14 +433,14 @@
|
|||||||
<item quantity="other">%d categories</item>
|
<item quantity="other">%d categories</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="action_display_unread_badge">Capítols no llegits</string>
|
<string name="action_display_unread_badge">Capítols no llegits</string>
|
||||||
<string name="tracking_info">Sincronització unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment. Configureu el seguiment d\'entrades individuals de manga al seu botó de seguiment.</string>
|
<string name="tracking_info">La sincronització és unidireccional per a actualitzar el progrés dels capítols als serveis de seguiment. Configureu el seguiment d\'elements individuals al seu botó de seguiment.</string>
|
||||||
<string name="pref_refresh_library_covers">Refresca les portades de la biblioteca</string>
|
<string name="pref_refresh_library_covers">Refresca les portades de la biblioteca</string>
|
||||||
<string name="unofficial_extension_message">Aquesta extensió no pertany a la llista d\'extensions oficials del Tachiyomi.</string>
|
<string name="unofficial_extension_message">Aquesta extensió no pertany a la llista d\'extensions oficials del Tachiyomi.</string>
|
||||||
<string name="ext_unofficial">No oficial</string>
|
<string name="ext_unofficial">No oficial</string>
|
||||||
<string name="sort_by_upload_date">Per data de pujada</string>
|
<string name="sort_by_upload_date">Per data de pujada</string>
|
||||||
<string name="label_data">Dades</string>
|
<string name="label_data">Dades</string>
|
||||||
<string name="backup_restore_missing_sources">Manquen fonts:</string>
|
<string name="backup_restore_missing_sources">Manquen fonts:</string>
|
||||||
<string name="invalid_backup_file_missing_manga">La còpia de seguretat no conté cap manga.</string>
|
<string name="invalid_backup_file_missing_manga">La còpia de seguretat no conté cap element de la biblioteca.</string>
|
||||||
<string name="invalid_backup_file">Fitxer de còpia de seguretat invàlid</string>
|
<string name="invalid_backup_file">Fitxer de còpia de seguretat invàlid</string>
|
||||||
<string name="pref_library_update_refresh_metadata_summary">Comprova si hi ha noves portades o detalls en actualitzar la biblioteca</string>
|
<string name="pref_library_update_refresh_metadata_summary">Comprova si hi ha noves portades o detalls en actualitzar la biblioteca</string>
|
||||||
<string name="pref_library_update_refresh_metadata">Refresca les metadades automàticament</string>
|
<string name="pref_library_update_refresh_metadata">Refresca les metadades automàticament</string>
|
||||||
@ -499,13 +499,13 @@
|
|||||||
<string name="no_chapters_error">No s\'ha trobat cap capítol</string>
|
<string name="no_chapters_error">No s\'ha trobat cap capítol</string>
|
||||||
<string name="chapter_settings_updated">S\'ha actualitzat la configuració per defecte dels capítols</string>
|
<string name="chapter_settings_updated">S\'ha actualitzat la configuració per defecte dels capítols</string>
|
||||||
<string name="set_chapter_settings_as_default">Estableix com a per defecte</string>
|
<string name="set_chapter_settings_as_default">Estableix com a per defecte</string>
|
||||||
<string name="also_set_chapter_settings_for_library">Aplica-ho també a tot el manga de la biblioteca</string>
|
<string name="also_set_chapter_settings_for_library">Aplica-ho també a tots els elements de la biblioteca</string>
|
||||||
<string name="confirm_set_chapter_settings">Esteu segur que voleu desar aquesta configuració com a configuració per defecte\?</string>
|
<string name="confirm_set_chapter_settings">Esteu segur que voleu desar aquesta configuració com a configuració per defecte\?</string>
|
||||||
<string name="chapter_settings">Configuració dels capítols</string>
|
<string name="chapter_settings">Configuració dels capítols</string>
|
||||||
<string name="share_page_info">%1$s: %2$s, pàgina %3$d</string>
|
<string name="share_page_info">%1$s: %2$s, pàgina %3$d</string>
|
||||||
<string name="action_search_settings">Configuració de la cerca</string>
|
<string name="action_search_settings">Configuració de la cerca</string>
|
||||||
<string name="downloaded_chapters">Capítols baixats</string>
|
<string name="downloaded_chapters">Capítols baixats</string>
|
||||||
<string name="manga_from_library">Manga de la biblioteca</string>
|
<string name="manga_from_library">De la biblioteca</string>
|
||||||
<string name="clear_history_confirmation">N’esteu segur\? Es perdrà tot l’historial.</string>
|
<string name="clear_history_confirmation">N’esteu segur\? Es perdrà tot l’historial.</string>
|
||||||
<string name="pref_incognito_mode_summary">Pausa l\'historial de lectura</string>
|
<string name="pref_incognito_mode_summary">Pausa l\'historial de lectura</string>
|
||||||
<string name="pref_incognito_mode">Mode d\'incògnit</string>
|
<string name="pref_incognito_mode">Mode d\'incògnit</string>
|
||||||
@ -548,8 +548,8 @@
|
|||||||
<string name="clipboard_copy_error">No s\'ha pogut copiar al porta-retalls</string>
|
<string name="clipboard_copy_error">No s\'ha pogut copiar al porta-retalls</string>
|
||||||
<string name="notification_incognito_text">Desactiva el mode d\'incògnit</string>
|
<string name="notification_incognito_text">Desactiva el mode d\'incògnit</string>
|
||||||
<string name="pref_dns_over_https">DNS sobre HTTPS (DoH)</string>
|
<string name="pref_dns_over_https">DNS sobre HTTPS (DoH)</string>
|
||||||
<string name="pref_download_new_categories_details">El manga de les categories excloses no es baixarà encara que també sigui a les categories incloses.</string>
|
<string name="pref_download_new_categories_details">Els elements de les categories excloses no es baixaran encara que també siguin a les categories incloses.</string>
|
||||||
<string name="pref_library_update_categories_details">El manga de les categories excloses no s\'actualitzarà encara que també sigui a les categories incloses.</string>
|
<string name="pref_library_update_categories_details">Els elements de les categories excloses no s\'actualitzaran encara que també siguin a les categories incloses.</string>
|
||||||
<string name="pref_category_auto_download">Baixada automàtica</string>
|
<string name="pref_category_auto_download">Baixada automàtica</string>
|
||||||
<string name="rotation_landscape">Horitzontal</string>
|
<string name="rotation_landscape">Horitzontal</string>
|
||||||
<string name="rotation_portrait">Vertical</string>
|
<string name="rotation_portrait">Vertical</string>
|
||||||
@ -559,7 +559,7 @@
|
|||||||
<string name="nav_zone_next">Següent</string>
|
<string name="nav_zone_next">Següent</string>
|
||||||
<string name="nav_zone_prev">Anterior</string>
|
<string name="nav_zone_prev">Anterior</string>
|
||||||
<string name="automatic_background">Automàtic</string>
|
<string name="automatic_background">Automàtic</string>
|
||||||
<string name="pref_create_folder_per_manga_summary">Crea carpetes segons el títol del manga</string>
|
<string name="pref_create_folder_per_manga_summary">Crea carpetes segons el títol dels elements</string>
|
||||||
<string name="pref_create_folder_per_manga">Desa les pàgines en carpetes separades</string>
|
<string name="pref_create_folder_per_manga">Desa les pàgines en carpetes separades</string>
|
||||||
<string name="pref_reader_actions">Accions</string>
|
<string name="pref_reader_actions">Accions</string>
|
||||||
<string name="pref_grayscale">Escala de grisos</string>
|
<string name="pref_grayscale">Escala de grisos</string>
|
||||||
@ -570,7 +570,7 @@
|
|||||||
<string name="none">Cap</string>
|
<string name="none">Cap</string>
|
||||||
<string name="action_show_errors">Premeu per a veure\'n els detalls</string>
|
<string name="action_show_errors">Premeu per a veure\'n els detalls</string>
|
||||||
<string name="cancel_all_for_series">Cancel·la-ho tot per a aquesta sèrie</string>
|
<string name="cancel_all_for_series">Cancel·la-ho tot per a aquesta sèrie</string>
|
||||||
<string name="action_sort_chapter_fetch_date">Data d\'obtenció del capítol</string>
|
<string name="action_sort_chapter_fetch_date">Data d\'obtenció dels capítols</string>
|
||||||
<string name="date">Data</string>
|
<string name="date">Data</string>
|
||||||
<string name="local_filter_order_by">Ordena per</string>
|
<string name="local_filter_order_by">Ordena per</string>
|
||||||
<string name="local_invalid_format">El format del capítol no és vàlid</string>
|
<string name="local_invalid_format">El format del capítol no és vàlid</string>
|
||||||
@ -586,7 +586,7 @@
|
|||||||
<string name="on">Activat</string>
|
<string name="on">Activat</string>
|
||||||
<string name="categorized_display_settings">Opcions de visualització i ordenació per categoria</string>
|
<string name="categorized_display_settings">Opcions de visualització i ordenació per categoria</string>
|
||||||
<string name="restrictions">Restriccions: %s</string>
|
<string name="restrictions">Restriccions: %s</string>
|
||||||
<string name="action_display_local_badge">Manga local</string>
|
<string name="action_display_local_badge">Font local</string>
|
||||||
<string name="pref_lowest">La més baixa</string>
|
<string name="pref_lowest">La més baixa</string>
|
||||||
<string name="pref_low">Baixa</string>
|
<string name="pref_low">Baixa</string>
|
||||||
<string name="pref_high">Alta</string>
|
<string name="pref_high">Alta</string>
|
||||||
@ -606,7 +606,7 @@
|
|||||||
<string name="theme_greenapple">Verd poma</string>
|
<string name="theme_greenapple">Verd poma</string>
|
||||||
<string name="pref_category_appearance">Aparença</string>
|
<string name="pref_category_appearance">Aparença</string>
|
||||||
<string name="action_start_downloading_now">Inicia la baixada ara</string>
|
<string name="action_start_downloading_now">Inicia la baixada ara</string>
|
||||||
<string name="action_sort_count">Nombre total de manga</string>
|
<string name="action_sort_count">Nombre total d\'elements</string>
|
||||||
<string name="pref_app_theme">Tema de l\'aplicació</string>
|
<string name="pref_app_theme">Tema de l\'aplicació</string>
|
||||||
<string name="theme_monet">Dinàmic</string>
|
<string name="theme_monet">Dinàmic</string>
|
||||||
<string name="recently">Recentment</string>
|
<string name="recently">Recentment</string>
|
||||||
@ -640,14 +640,14 @@
|
|||||||
<string name="ext_installer_pref">Instal·lador</string>
|
<string name="ext_installer_pref">Instal·lador</string>
|
||||||
<string name="ext_installer_legacy">Antic</string>
|
<string name="ext_installer_legacy">Antic</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Buida la memòria cau de capítols en tancar l\'aplicació</string>
|
<string name="pref_auto_clear_chapter_cache">Buida la memòria cau de capítols en tancar l\'aplicació</string>
|
||||||
<string name="enhanced_tracking_info">Serveix que proporcionen funcionalitats millorades per a fonts específiques. El manga se segueix automàticament en afegir-lo a la vostra biblioteca.</string>
|
<string name="enhanced_tracking_info">Aquests serveis proporcionen funcionalitats millorades per a fonts específiques. Els elements se segueixen automàticament en afegir-los a la vostra biblioteca.</string>
|
||||||
<string name="about_dont_kill_my_app">Alguns fabricants tenen restriccions addicionals per a les aplicacions que finalitzen els serveis en segon pla. Aquest lloc web té més informació de com solucionar-ho.</string>
|
<string name="about_dont_kill_my_app">Alguns fabricants tenen restriccions addicionals per a les aplicacions que finalitzen els serveis en segon pla. Aquest lloc web té més informació de com solucionar-ho.</string>
|
||||||
<string name="clear_database_source_item_count">Hi ha %1$d manga que no és a la biblioteca a la base de dades</string>
|
<string name="clear_database_source_item_count">Hi ha %1$d elements a la base de dades que no són a la biblioteca</string>
|
||||||
<string name="cancelled">Cancel·lada</string>
|
<string name="cancelled">Cancel·lada</string>
|
||||||
<string name="library_errors_help">Per a obtenir ajuda per a resoldre errors d\'actualització de la biblioteca, vegeu %1$s</string>
|
<string name="library_errors_help">Per a obtenir ajuda per a resoldre errors d\'actualització de la biblioteca, vegeu %1$s</string>
|
||||||
<string name="extension_api_error">No s\'ha pogut obtenir la llista d\'extensions</string>
|
<string name="extension_api_error">No s\'ha pogut obtenir la llista d\'extensions</string>
|
||||||
<string name="action_faq_and_guides">PMF i guies</string>
|
<string name="action_faq_and_guides">PMF i guies</string>
|
||||||
<string name="pref_library_update_manga_restriction">Omet les actualitzacions dels títols</string>
|
<string name="pref_library_update_manga_restriction">Omet les actualitzacions dels elements</string>
|
||||||
<string name="pref_update_only_completely_read">Amb capítols no llegits</string>
|
<string name="pref_update_only_completely_read">Amb capítols no llegits</string>
|
||||||
<string name="pref_library_update_show_tab_badge">Mostra el comptador de no llegits a la icona d\'actualitzacions</string>
|
<string name="pref_library_update_show_tab_badge">Mostra el comptador de no llegits a la icona d\'actualitzacions</string>
|
||||||
<string name="webtoon_side_padding_5">5%</string>
|
<string name="webtoon_side_padding_5">5%</string>
|
||||||
@ -664,7 +664,7 @@
|
|||||||
<string name="download_queue_size_warning">Advertència: Les baixades massa grosses poden fer que les fonts es tornin més lentes i/o bloquin el Tachiyomi. Premeu per a obtenir-ne més informació.</string>
|
<string name="download_queue_size_warning">Advertència: Les baixades massa grosses poden fer que les fonts es tornin més lentes i/o bloquin el Tachiyomi. Premeu per a obtenir-ne més informació.</string>
|
||||||
<string name="notification_size_warning">Les actualitzacions grosses perjudiquen les fonts i poden implicar actualitzacions més lentes i un augment en l\'ús de bateria. Premeu per a obtenir-ne més informació.</string>
|
<string name="notification_size_warning">Les actualitzacions grosses perjudiquen les fonts i poden implicar actualitzacions més lentes i un augment en l\'ús de bateria. Premeu per a obtenir-ne més informació.</string>
|
||||||
<string name="pref_landscape_zoom">Amplia la imatge en horitzontal</string>
|
<string name="pref_landscape_zoom">Amplia la imatge en horitzontal</string>
|
||||||
<string name="action_show_manga">Mostra el manga</string>
|
<string name="action_show_manga">Mostra l\'element</string>
|
||||||
<string name="confirm_manga_add_duplicate">Teniu un element a la vostra biblioteca amb el mateix nom però d\'una font diferent (%1$s).
|
<string name="confirm_manga_add_duplicate">Teniu un element a la vostra biblioteca amb el mateix nom però d\'una font diferent (%1$s).
|
||||||
\n
|
\n
|
||||||
\nVoleu continuar igualment\?</string>
|
\nVoleu continuar igualment\?</string>
|
||||||
@ -695,7 +695,7 @@
|
|||||||
<string name="source_filter_empty_screen">No s\'ha trobat cap font instal·lada</string>
|
<string name="source_filter_empty_screen">No s\'ha trobat cap font instal·lada</string>
|
||||||
<string name="source_empty_screen">No s\'ha trobat cap font</string>
|
<string name="source_empty_screen">No s\'ha trobat cap font</string>
|
||||||
<string name="action_sort_unread_count">Nombre de no llegits</string>
|
<string name="action_sort_unread_count">Nombre de no llegits</string>
|
||||||
<string name="action_sort_last_manga_update">Darrera actualització de manga</string>
|
<string name="action_sort_last_manga_update">Darrera comprovació d\'actualitzacions</string>
|
||||||
<string name="split_tall_images">Divideix les imatges altes</string>
|
<string name="split_tall_images">Divideix les imatges altes</string>
|
||||||
<string name="split_tall_images_summary">Millora el rendiment del lector</string>
|
<string name="split_tall_images_summary">Millora el rendiment del lector</string>
|
||||||
<string name="download_notifier_split_page_not_found">No s\'ha trobat la pàgina %d en dividir</string>
|
<string name="download_notifier_split_page_not_found">No s\'ha trobat la pàgina %d en dividir</string>
|
||||||
@ -728,7 +728,7 @@
|
|||||||
<string name="pref_reset_user_agent_string">Restableix la cadena d\'agent d\'usuari per defecte</string>
|
<string name="pref_reset_user_agent_string">Restableix la cadena d\'agent d\'usuari per defecte</string>
|
||||||
<string name="appwidget_unavailable_locked">El widget no està disponible quan hi ha activat el blocatge de l\'aplicació</string>
|
<string name="appwidget_unavailable_locked">El widget no està disponible quan hi ha activat el blocatge de l\'aplicació</string>
|
||||||
<string name="loader_rar5_error">El format RARv5 no està suportat</string>
|
<string name="loader_rar5_error">El format RARv5 no està suportat</string>
|
||||||
<string name="appwidget_updates_description">Vegeu els vostres mangues actualitzats recentment</string>
|
<string name="appwidget_updates_description">Vegeu els elements de la biblioteca actualitzats recentment</string>
|
||||||
<string name="action_remove_everything">Elimina-ho tot</string>
|
<string name="action_remove_everything">Elimina-ho tot</string>
|
||||||
<string name="update_already_running">Ja s\'està executant una actualització</string>
|
<string name="update_already_running">Ja s\'està executant una actualització</string>
|
||||||
<string name="theme_tidalwave">Tsunami</string>
|
<string name="theme_tidalwave">Tsunami</string>
|
||||||
@ -746,7 +746,7 @@
|
|||||||
<item quantity="other">Els següents %d capítols no llegits</item>
|
<item quantity="other">Els següents %d capítols no llegits</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="missing_storage_permission">No s\'han concedit permisos d\'emmagatzematge</string>
|
<string name="missing_storage_permission">No s\'han concedit permisos d\'emmagatzematge</string>
|
||||||
<string name="popular">Popular</string>
|
<string name="popular">Populars</string>
|
||||||
<string name="pref_backup_summary">Còpies de seguretat automàtiques i manuals</string>
|
<string name="pref_backup_summary">Còpies de seguretat automàtiques i manuals</string>
|
||||||
<string name="pref_reader_summary">Mode de lectura, visualització i navegació</string>
|
<string name="pref_reader_summary">Mode de lectura, visualització i navegació</string>
|
||||||
<string name="pref_downloads_summary">Baixades automàtiques i per avançat</string>
|
<string name="pref_downloads_summary">Baixades automàtiques i per avançat</string>
|
||||||
@ -765,5 +765,11 @@
|
|||||||
<string name="remove_manga">Suprimireu «%s» de la vostra biblioteca</string>
|
<string name="remove_manga">Suprimireu «%s» de la vostra biblioteca</string>
|
||||||
<string name="pref_long_strip_split">Divideix les imatges altes (BETA)</string>
|
<string name="pref_long_strip_split">Divideix les imatges altes (BETA)</string>
|
||||||
<string name="action_search_hint">Cerca…</string>
|
<string name="action_search_hint">Cerca…</string>
|
||||||
<string name="updates_last_update_info">Biblioteca actualitzada per darrer cop: %s</string>
|
<string name="updates_last_update_info">Biblioteca actualitzada per darrera vegada: %s</string>
|
||||||
|
<string name="download_notifier_cache_renewal">S\'estan indexant les baixades</string>
|
||||||
|
<string name="channel_downloader_cache">Memòria cau de baixades</string>
|
||||||
|
<string name="action_open_random_manga">Obre un element aleatori</string>
|
||||||
|
<string name="fdroid_warning">Les compilacions de F-Droid no tenen assistència oficial.
|
||||||
|
\nPremeu per a obtenir-ne més informació.</string>
|
||||||
|
<string name="information_no_entries_found">No s\'ha trobat cap element en aquesta categoria</string>
|
||||||
</resources>
|
</resources>
|
@ -145,7 +145,7 @@
|
|||||||
<string name="update_check_confirm">Stáhnout</string>
|
<string name="update_check_confirm">Stáhnout</string>
|
||||||
<string name="update_check_no_new_updates">Žádné nové aktualizace</string>
|
<string name="update_check_no_new_updates">Žádné nové aktualizace</string>
|
||||||
<string name="update_check_look_for_updates">Hledání aktualizací…</string>
|
<string name="update_check_look_for_updates">Hledání aktualizací…</string>
|
||||||
<string name="update_check_notification_download_complete">Klepnutím nainstalujte</string>
|
<string name="update_check_notification_download_complete">Klepnutím nainstalujte aktualizaci</string>
|
||||||
<string name="update_check_notification_download_error">Chyba při stahování</string>
|
<string name="update_check_notification_download_error">Chyba při stahování</string>
|
||||||
<string name="update_check_notification_update_available">Dostupná aktualizace!</string>
|
<string name="update_check_notification_update_available">Dostupná aktualizace!</string>
|
||||||
<string name="information_no_recent">Žádné nedávné aktualizace</string>
|
<string name="information_no_recent">Žádné nedávné aktualizace</string>
|
||||||
@ -308,7 +308,7 @@
|
|||||||
<string name="action_webview_refresh">Obnovit</string>
|
<string name="action_webview_refresh">Obnovit</string>
|
||||||
<string name="pref_category_library">Knihovna</string>
|
<string name="pref_category_library">Knihovna</string>
|
||||||
<string name="ext_obsolete">Zastaralý</string>
|
<string name="ext_obsolete">Zastaralý</string>
|
||||||
<string name="obsolete_extension_message">Tohle rozšíření již není dostupné.</string>
|
<string name="obsolete_extension_message">Toto rozšíření již není k dispozici. Nemusí fungovat správně a může způsobit problémy s aplikací. Doporučujeme jej odinstalovat.</string>
|
||||||
<string name="logout">Odhlásit se</string>
|
<string name="logout">Odhlásit se</string>
|
||||||
<string name="pref_date_format">Formát data</string>
|
<string name="pref_date_format">Formát data</string>
|
||||||
<string name="pref_category_library_update">Globální aktualizace</string>
|
<string name="pref_category_library_update">Globální aktualizace</string>
|
||||||
@ -488,9 +488,9 @@
|
|||||||
<item quantity="other">%1$d nových kapitol</item>
|
<item quantity="other">%1$d nových kapitol</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="notification_new_chapters_summary">
|
<plurals name="notification_new_chapters_summary">
|
||||||
<item quantity="one">Pro %d titul</item>
|
<item quantity="one">Pro %d položku</item>
|
||||||
<item quantity="few">Pro %d tituly</item>
|
<item quantity="few">Pro %d položky</item>
|
||||||
<item quantity="other">Pro %d titulů</item>
|
<item quantity="other">Pro %d položek</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="notification_check_updates">Hledám nové kapitoly</string>
|
<string name="notification_check_updates">Hledám nové kapitoly</string>
|
||||||
<string name="download_insufficient_space">Nelze stáhnout kapitoly kvůli nedostatku místa</string>
|
<string name="download_insufficient_space">Nelze stáhnout kapitoly kvůli nedostatku místa</string>
|
||||||
@ -567,7 +567,7 @@
|
|||||||
<string name="rotation_landscape">Na šířku</string>
|
<string name="rotation_landscape">Na šířku</string>
|
||||||
<string name="rotation_portrait">Na výšku</string>
|
<string name="rotation_portrait">Na výšku</string>
|
||||||
<string name="rotation_type">Typ otočení</string>
|
<string name="rotation_type">Typ otočení</string>
|
||||||
<string name="pref_create_folder_per_manga_summary">Vytváří složky podle názvů položek</string>
|
<string name="pref_create_folder_per_manga_summary">Vytváří složky podle názvu položky</string>
|
||||||
<string name="pref_create_folder_per_manga">Uložit stránky do samostatných složek</string>
|
<string name="pref_create_folder_per_manga">Uložit stránky do samostatných složek</string>
|
||||||
<string name="pref_reader_actions">Akce</string>
|
<string name="pref_reader_actions">Akce</string>
|
||||||
<string name="nav_zone_right">Vpravo</string>
|
<string name="nav_zone_right">Vpravo</string>
|
||||||
@ -660,12 +660,12 @@
|
|||||||
<string name="pref_verbose_logging_summary">Vypisovat podrobné informace do systémového protokolu (sníží výkon aplikace)</string>
|
<string name="pref_verbose_logging_summary">Vypisovat podrobné informace do systémového protokolu (sníží výkon aplikace)</string>
|
||||||
<string name="channel_app_updates">Aktualizace aplikace</string>
|
<string name="channel_app_updates">Aktualizace aplikace</string>
|
||||||
<string name="notification_size_warning">Varování: velké aktualizace poškozují zdroje a můžou vést k pomalejším aktualizacím a zvýšenému využití baterie. Klepnutím se dozvíte více.</string>
|
<string name="notification_size_warning">Varování: velké aktualizace poškozují zdroje a můžou vést k pomalejším aktualizacím a zvýšenému využití baterie. Klepnutím se dozvíte více.</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Vymazat cache kapitol při zavření aplikace</string>
|
<string name="pref_auto_clear_chapter_cache">Vymazat mezipaměť kapitol při zavření aplikace</string>
|
||||||
<string name="extension_api_error">Chyba v získání seznamu rozšíření</string>
|
<string name="extension_api_error">Chyba v získání seznamu rozšíření</string>
|
||||||
<string name="privacy_policy">Zásady ochrany osobních údajů</string>
|
<string name="privacy_policy">Zásady ochrany osobních údajů</string>
|
||||||
<string name="clear_database_source_item_count">%1$d neknihovní záznamy v databázi</string>
|
<string name="clear_database_source_item_count">%1$d neknihovní záznamy v databázi</string>
|
||||||
<string name="pref_true_color_summary">Snižuje pruhování barev, ale může mít vliv na výkon</string>
|
<string name="pref_true_color_summary">Snižuje pruhování barev, ale může mít vliv na výkon</string>
|
||||||
<string name="pref_library_update_manga_restriction">Přeskočit aktualizaci titulů</string>
|
<string name="pref_library_update_manga_restriction">Přeskočit aktualizování položek</string>
|
||||||
<string name="pref_update_only_completely_read">S nepřečtenými kapitolami</string>
|
<string name="pref_update_only_completely_read">S nepřečtenými kapitolami</string>
|
||||||
<string name="database_clean">Nic k vyčištění</string>
|
<string name="database_clean">Nic k vyčištění</string>
|
||||||
<string name="save_chapter_as_cbz">Uložit jako CBZ archiv</string>
|
<string name="save_chapter_as_cbz">Uložit jako CBZ archiv</string>
|
||||||
@ -779,4 +779,10 @@
|
|||||||
<string name="unknown_title">Neznámý titul</string>
|
<string name="unknown_title">Neznámý titul</string>
|
||||||
<string name="error_user_agent_string_invalid">Neplatný řetězec uživatelského agenta</string>
|
<string name="error_user_agent_string_invalid">Neplatný řetězec uživatelského agenta</string>
|
||||||
<string name="updates_last_update_info_just_now">Právě teď</string>
|
<string name="updates_last_update_info_just_now">Právě teď</string>
|
||||||
|
<string name="download_notifier_cache_renewal">Indexování stažených souborů</string>
|
||||||
|
<string name="channel_downloader_cache">Stáhnout mezipaměť</string>
|
||||||
|
<string name="information_no_entries_found">V této kategorii nebyly nalezeny žádné položky</string>
|
||||||
|
<string name="action_open_random_manga">Otevřít náhodnou položku</string>
|
||||||
|
<string name="fdroid_warning">F-Droid sestavení nejsou oficiálně podporovány.
|
||||||
|
\nKlepnutím zobrazíte další informace.</string>
|
||||||
</resources>
|
</resources>
|
@ -559,4 +559,31 @@
|
|||||||
<string name="pref_show_navigation_mode_summary">Пусма вырӑнсене вулӑш уҫӑ чухне кӑтартмалла</string>
|
<string name="pref_show_navigation_mode_summary">Пусма вырӑнсене вулӑш уҫӑ чухне кӑтартмалла</string>
|
||||||
<string name="action_show_errors">Йӑнӑшсене кӑтарт</string>
|
<string name="action_show_errors">Йӑнӑшсене кӑтарт</string>
|
||||||
<string name="cancel_all_for_series">Ҫак серилӗх валли веҫ пӑрахӑҫла</string>
|
<string name="cancel_all_for_series">Ҫак серилӗх валли веҫ пӑрахӑҫла</string>
|
||||||
|
<string name="pref_downloads_summary">Хӑй-хальлӗн тийесе илни, малтан тийени</string>
|
||||||
|
<string name="action_sort_last_manga_update">Юлашки ҫӗнетӗве тӗрӗслени</string>
|
||||||
|
<string name="action_sort_unread_count">Юлнӑ сыпӑксем</string>
|
||||||
|
<string name="action_sort_count">Пурӗ ҫырав</string>
|
||||||
|
<string name="action_remove_everything">Веҫех катерт</string>
|
||||||
|
<string name="delete_category_confirmation">«%s» пухмӑша катертесшӗнех-и\?</string>
|
||||||
|
<string name="delete_category">Пухмӑша катерт</string>
|
||||||
|
<string name="action_display_local_badge">Вырӑнти ҫӑл куҫ</string>
|
||||||
|
<string name="label_warning">Асӑрхаттару</string>
|
||||||
|
<string name="action_display_cover_only_grid">Ятсӑр сетке</string>
|
||||||
|
<string name="action_move_to_top_all_for_series">Серие пуҫламӑша куҫар</string>
|
||||||
|
<string name="confirm_lock_change">Улшӑнӑва ҫирӗплетме аутентификацилен</string>
|
||||||
|
<string name="action_filter_started">Пуҫланӑ</string>
|
||||||
|
<string name="action_faq_and_guides">Кӑтартусем тата ыйту-хурав</string>
|
||||||
|
<string name="action_show_manga">Ҫырава кӑтарт</string>
|
||||||
|
<string name="action_display_language_badge">Чӗлхе</string>
|
||||||
|
<string name="action_search_hint">Шыра…</string>
|
||||||
|
<string name="action_close">Хуп</string>
|
||||||
|
<string name="action_start_downloading_now">Тиеве халь пуҫла</string>
|
||||||
|
<string name="internal_error">InternalError: Хушма пӗлӗме пӑхма тӑвӑмсен кӗнекине тӗрӗсле</string>
|
||||||
|
<string name="pref_category_appearance">Кӑтартӑнни</string>
|
||||||
|
<string name="on">Ҫутнӑ</string>
|
||||||
|
<string name="off">Сӳнтернӗ</string>
|
||||||
|
<string name="pref_appearance_summary">Тема, кун тата вӑхӑт хармачӗ</string>
|
||||||
|
<string name="pref_library_summary">Пухмӑшсем, пӗтӗмӗшле ҫӗнетӳ</string>
|
||||||
|
<string name="pref_reader_summary">Вулав тытӑмӗ, кӑтартӑнни, куҫӑм</string>
|
||||||
|
<string name="pref_general_summary">Хушӑм чӗлхи, систерӳсем</string>
|
||||||
</resources>
|
</resources>
|
@ -221,7 +221,7 @@
|
|||||||
<string name="update_check_no_new_updates">Keine neue Aktualisierung verfügbar</string>
|
<string name="update_check_no_new_updates">Keine neue Aktualisierung verfügbar</string>
|
||||||
<string name="update_check_look_for_updates">Suche nach Aktualisierungen…</string>
|
<string name="update_check_look_for_updates">Suche nach Aktualisierungen…</string>
|
||||||
<string name="update_check_notification_download_in_progress">Herunterladen…</string>
|
<string name="update_check_notification_download_in_progress">Herunterladen…</string>
|
||||||
<string name="update_check_notification_download_complete">Tippe zum Installieren</string>
|
<string name="update_check_notification_download_complete">Tippe, um die Aktualisierung zu installieren</string>
|
||||||
<string name="update_check_notification_download_error">Fehler beim Herunterladen</string>
|
<string name="update_check_notification_download_error">Fehler beim Herunterladen</string>
|
||||||
<string name="update_check_notification_update_available">Neue Version verfügbar!</string>
|
<string name="update_check_notification_update_available">Neue Version verfügbar!</string>
|
||||||
<string name="information_no_downloads">Keine Downloads</string>
|
<string name="information_no_downloads">Keine Downloads</string>
|
||||||
@ -308,7 +308,7 @@
|
|||||||
<string name="action_webview_refresh">Aktualisieren</string>
|
<string name="action_webview_refresh">Aktualisieren</string>
|
||||||
<string name="pref_category_library">Bibliothek</string>
|
<string name="pref_category_library">Bibliothek</string>
|
||||||
<string name="ext_obsolete">Veraltet</string>
|
<string name="ext_obsolete">Veraltet</string>
|
||||||
<string name="obsolete_extension_message">Diese Erweiterung ist nicht länger verfügbar.</string>
|
<string name="obsolete_extension_message">Diese Erweiterung ist nicht länger verfügbar. Sie funktioniert möglicherweise nicht mehr ordnungsgemäß und kann Probleme mit der App verursachen. Es ist empfohlen, sie zu deinstallieren.</string>
|
||||||
<string name="pref_date_format">Datumsformat</string>
|
<string name="pref_date_format">Datumsformat</string>
|
||||||
<string name="pref_category_library_update">Globale Aktualisierung</string>
|
<string name="pref_category_library_update">Globale Aktualisierung</string>
|
||||||
<string name="logout_title">Aus %1$s abmelden\?</string>
|
<string name="logout_title">Aus %1$s abmelden\?</string>
|
||||||
@ -361,8 +361,8 @@
|
|||||||
<string name="email">E-Mail-Adresse</string>
|
<string name="email">E-Mail-Adresse</string>
|
||||||
<string name="pref_always_show_chapter_transition">Kapitelübergang immer anzeigen</string>
|
<string name="pref_always_show_chapter_transition">Kapitelübergang immer anzeigen</string>
|
||||||
<plurals name="notification_new_chapters_summary">
|
<plurals name="notification_new_chapters_summary">
|
||||||
<item quantity="one">Für %d Titel</item>
|
<item quantity="one">Für %d Eintrag</item>
|
||||||
<item quantity="other">Für %d Titel</item>
|
<item quantity="other">Für %d Einträge</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="action_menu">Menü</string>
|
<string name="action_menu">Menü</string>
|
||||||
<string name="action_reorganize_by">Umordnen</string>
|
<string name="action_reorganize_by">Umordnen</string>
|
||||||
@ -560,7 +560,7 @@
|
|||||||
<string name="clipboard_copy_error">Kopieren in die Zwischenablage fehlgeschlagen</string>
|
<string name="clipboard_copy_error">Kopieren in die Zwischenablage fehlgeschlagen</string>
|
||||||
<string name="rotation_landscape">Querformat</string>
|
<string name="rotation_landscape">Querformat</string>
|
||||||
<string name="rotation_portrait">Hochformat</string>
|
<string name="rotation_portrait">Hochformat</string>
|
||||||
<string name="pref_create_folder_per_manga_summary">Erstellt Ordner nach den Titeln der Einträge</string>
|
<string name="pref_create_folder_per_manga_summary">Erstellt Ordner nach dem Titel der Einträge</string>
|
||||||
<string name="pref_create_folder_per_manga">Speichere Seiten in separate Ordner</string>
|
<string name="pref_create_folder_per_manga">Speichere Seiten in separate Ordner</string>
|
||||||
<string name="rotation_type">Ausrichtungstyp</string>
|
<string name="rotation_type">Ausrichtungstyp</string>
|
||||||
<string name="pref_reader_actions">Aktionen</string>
|
<string name="pref_reader_actions">Aktionen</string>
|
||||||
@ -655,7 +655,7 @@
|
|||||||
<string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string>
|
<string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string>
|
||||||
<string name="privacy_policy">Datenschutzbestimmungen</string>
|
<string name="privacy_policy">Datenschutzbestimmungen</string>
|
||||||
<string name="pref_update_only_completely_read">Mit ungelesenen Kapiteln</string>
|
<string name="pref_update_only_completely_read">Mit ungelesenen Kapiteln</string>
|
||||||
<string name="pref_library_update_manga_restriction">Aktualisierung der Titel überspringen</string>
|
<string name="pref_library_update_manga_restriction">Aktualisierung der Einträge überspringen</string>
|
||||||
<string name="library_errors_help">Für Hilfe zum Beheben von Fehlern bei Bibliotheksaktualisierungen, siehe %1$s</string>
|
<string name="library_errors_help">Für Hilfe zum Beheben von Fehlern bei Bibliotheksaktualisierungen, siehe %1$s</string>
|
||||||
<string name="save_chapter_as_cbz">Als CBZ-Archiv speichern</string>
|
<string name="save_chapter_as_cbz">Als CBZ-Archiv speichern</string>
|
||||||
<string name="cancelled">Abgebrochen</string>
|
<string name="cancelled">Abgebrochen</string>
|
||||||
@ -766,4 +766,10 @@
|
|||||||
<string name="invalid_location">Ungültiger Speicherort: %s</string>
|
<string name="invalid_location">Ungültiger Speicherort: %s</string>
|
||||||
<string name="error_user_agent_string_invalid">Ungültiger User-Agent-Text</string>
|
<string name="error_user_agent_string_invalid">Ungültiger User-Agent-Text</string>
|
||||||
<string name="updates_last_update_info_just_now">Gerade eben</string>
|
<string name="updates_last_update_info_just_now">Gerade eben</string>
|
||||||
|
<string name="channel_downloader_cache">Download-Zwischenspeicher</string>
|
||||||
|
<string name="download_notifier_cache_renewal">Downloads werden indiziert</string>
|
||||||
|
<string name="action_open_random_manga">Zufälligen Eintrag öffnen</string>
|
||||||
|
<string name="information_no_entries_found">Keine Einträge in dieser Kategorie gefunden</string>
|
||||||
|
<string name="fdroid_warning">F-Droid-Builds werden nicht offiziell unterstützt.
|
||||||
|
\nTippe, um mehr zu erfahren.</string>
|
||||||
</resources>
|
</resources>
|
@ -5,7 +5,7 @@
|
|||||||
<string name="manga">Manga</string>
|
<string name="manga">Manga</string>
|
||||||
<string name="chapters">Κεφάλαια</string>
|
<string name="chapters">Κεφάλαια</string>
|
||||||
<string name="track">Tracking</string>
|
<string name="track">Tracking</string>
|
||||||
<string name="history">Ιστορία</string>
|
<string name="history">Ιστορικό</string>
|
||||||
<string name="label_settings">Ρυθμίσεις</string>
|
<string name="label_settings">Ρυθμίσεις</string>
|
||||||
<string name="label_download_queue">Ουρά λήψεων</string>
|
<string name="label_download_queue">Ουρά λήψεων</string>
|
||||||
<string name="label_library">Βιβλιοθήκη</string>
|
<string name="label_library">Βιβλιοθήκη</string>
|
||||||
@ -169,7 +169,7 @@
|
|||||||
<string name="pref_backup_slots">Μέγιστα αντίγραφα ασφαλείας</string>
|
<string name="pref_backup_slots">Μέγιστα αντίγραφα ασφαλείας</string>
|
||||||
<string name="backup_created">Δημιουργήθηκε αντίγραφο ασφαλείας</string>
|
<string name="backup_created">Δημιουργήθηκε αντίγραφο ασφαλείας</string>
|
||||||
<string name="restore_completed">Η επαναφορά ολοκληρώθηκε</string>
|
<string name="restore_completed">Η επαναφορά ολοκληρώθηκε</string>
|
||||||
<string name="backup_choice">Τι θέλετε να κάνετε backup;</string>
|
<string name="backup_choice">Τι αντίγραφο ασφαλείας θέλετε να δημιουργήσετε;</string>
|
||||||
<string name="restoring_backup">Επαναφορά αντιγράφων ασφαλείας</string>
|
<string name="restoring_backup">Επαναφορά αντιγράφων ασφαλείας</string>
|
||||||
<string name="creating_backup">Δημιουργία αντιγράφων ασφαλείας</string>
|
<string name="creating_backup">Δημιουργία αντιγράφων ασφαλείας</string>
|
||||||
<string name="pref_clear_chapter_cache">Καθάρισμα προσωρινής μνήμης κεφαλαίου</string>
|
<string name="pref_clear_chapter_cache">Καθάρισμα προσωρινής μνήμης κεφαλαίου</string>
|
||||||
@ -179,8 +179,8 @@
|
|||||||
<string name="pref_clear_cookies">Διαγραφή cookies</string>
|
<string name="pref_clear_cookies">Διαγραφή cookies</string>
|
||||||
<string name="cookies_cleared">Τα cookies διαγράφηκαν</string>
|
<string name="cookies_cleared">Τα cookies διαγράφηκαν</string>
|
||||||
<string name="pref_clear_database">Καθαρισμός βάσης δεδομένων</string>
|
<string name="pref_clear_database">Καθαρισμός βάσης δεδομένων</string>
|
||||||
<string name="pref_clear_database_summary">Διαγραφή ιστορικού για manga που δεν είναι αποθηκευμένα στη βιβλιοθήκη σας</string>
|
<string name="pref_clear_database_summary">Διαγραφή ιστορικού για καταχωρήσεις που δεν έχουν αποθηκευτεί στη βιβλιοθήκη σας</string>
|
||||||
<string name="clear_database_confirmation">Είστε σίγουροι; Τα διαβασμένα κεφάλαια και η πρόοδος των manga εκτός βιβλιοθήκης θα χαθεί</string>
|
<string name="clear_database_confirmation">Είστε σίγουροι; Τα διαβασμένα κεφάλαια και η πρόοδος των καταχωρήσεων εκτός βιβλιοθήκης θα χαθούν</string>
|
||||||
<string name="clear_database_completed">Οι καταχωρίσεις διαγράφηκαν</string>
|
<string name="clear_database_completed">Οι καταχωρίσεις διαγράφηκαν</string>
|
||||||
<string name="pref_refresh_library_tracking">Ανανέωση tracking</string>
|
<string name="pref_refresh_library_tracking">Ανανέωση tracking</string>
|
||||||
<string name="pref_refresh_library_tracking_summary">Ενημερώνει κατάσταση, βαθμολογία και τελευταίο αναγνωσμένο κεφάλαιο από τις υπηρεσίες παρακολούθησης</string>
|
<string name="pref_refresh_library_tracking_summary">Ενημερώνει κατάσταση, βαθμολογία και τελευταίο αναγνωσμένο κεφάλαιο από τις υπηρεσίες παρακολούθησης</string>
|
||||||
@ -244,8 +244,8 @@
|
|||||||
<string name="error_category_exists">Μια κατηγορία με αυτό το όνομα υπάρχει ήδη!</string>
|
<string name="error_category_exists">Μια κατηγορία με αυτό το όνομα υπάρχει ήδη!</string>
|
||||||
<string name="snack_categories_deleted">Οι κατηγορίες διαγράφηκαν</string>
|
<string name="snack_categories_deleted">Οι κατηγορίες διαγράφηκαν</string>
|
||||||
<string name="dialog_with_checkbox_remove_description">Αυτό θα αφαιρέσει την ημερομηνία ανάγνωσης αυτού του κεφαλαίου. Είστε σίγουροι;</string>
|
<string name="dialog_with_checkbox_remove_description">Αυτό θα αφαιρέσει την ημερομηνία ανάγνωσης αυτού του κεφαλαίου. Είστε σίγουροι;</string>
|
||||||
<string name="dialog_with_checkbox_reset">Επαναφορά όλων των κεφαλαίων για αυτό το manga</string>
|
<string name="dialog_with_checkbox_reset">Επαναφορά όλων των κεφαλαίων για αυτήν την καταχώρηση</string>
|
||||||
<string name="snack_add_to_library">Προσθήκη manga στη βιβλιοθήκη;</string>
|
<string name="snack_add_to_library">Προσθήκη στη βιβλιοθήκη;</string>
|
||||||
<string name="picture_saved">Η εικόνα αποθηκεύτηκε</string>
|
<string name="picture_saved">Η εικόνα αποθηκεύτηκε</string>
|
||||||
<string name="custom_filter">Προσαρμοσμένο φίλτρο</string>
|
<string name="custom_filter">Προσαρμοσμένο φίλτρο</string>
|
||||||
<string name="set_as_cover">Ορισμός ως εξώφυλλο</string>
|
<string name="set_as_cover">Ορισμός ως εξώφυλλο</string>
|
||||||
@ -268,14 +268,14 @@
|
|||||||
<string name="download_queue_error">Δεν ήταν δυνατή η λήψη κεφαλαίων. Μπορείτε να δοκιμάσετε ξανά στο τμήμα λήψεων</string>
|
<string name="download_queue_error">Δεν ήταν δυνατή η λήψη κεφαλαίων. Μπορείτε να δοκιμάσετε ξανά στο τμήμα λήψεων</string>
|
||||||
<string name="notification_new_chapters">Βρέθηκαν νέα κεφάλαια</string>
|
<string name="notification_new_chapters">Βρέθηκαν νέα κεφάλαια</string>
|
||||||
<string name="notification_cover_update_failed">Δεν ήταν δυνατή η ενημέρωση του εξώφυλλου</string>
|
<string name="notification_cover_update_failed">Δεν ήταν δυνατή η ενημέρωση του εξώφυλλου</string>
|
||||||
<string name="notification_first_add_to_library">Παρακαλώ προσθέστε το manga στη βιβλιοθήκη σας πριν κάνετε κάτι τέτοιο</string>
|
<string name="notification_first_add_to_library">Παρακαλώ προσθέστε την καταχώρηση στη βιβλιοθήκη σας πριν το κάνετε αυτό</string>
|
||||||
<string name="file_select_cover">Επιλέξτε εικόνα εξωφύλλου</string>
|
<string name="file_select_cover">Επιλέξτε εικόνα εξωφύλλου</string>
|
||||||
<string name="file_select_backup">Επιλέξτε αρχείο αντιγράφου ασφαλείας</string>
|
<string name="file_select_backup">Επιλέξτε αρχείο αντιγράφου ασφαλείας</string>
|
||||||
<string name="update_check_confirm">Λήψη</string>
|
<string name="update_check_confirm">Λήψη</string>
|
||||||
<string name="update_check_no_new_updates">Δεν υπάρχουν διαθέσιμες νέες ενημερώσεις</string>
|
<string name="update_check_no_new_updates">Δεν υπάρχουν διαθέσιμες νέες ενημερώσεις</string>
|
||||||
<string name="update_check_look_for_updates">Αναζήτηση για ενημερώσεις…</string>
|
<string name="update_check_look_for_updates">Αναζήτηση για ενημερώσεις…</string>
|
||||||
<string name="update_check_notification_download_in_progress">Γίνεται λήψη…</string>
|
<string name="update_check_notification_download_in_progress">Γίνεται λήψη…</string>
|
||||||
<string name="update_check_notification_download_complete">Πατήστε για εγκατάσταση</string>
|
<string name="update_check_notification_download_complete">Πατήστε για να εγκαταστήσετε την ενημέρωση</string>
|
||||||
<string name="update_check_notification_download_error">Σφάλμα λήψης</string>
|
<string name="update_check_notification_download_error">Σφάλμα λήψης</string>
|
||||||
<string name="update_check_notification_update_available">Υπάρχει διαθέσιμη ενημέρωση!</string>
|
<string name="update_check_notification_update_available">Υπάρχει διαθέσιμη ενημέρωση!</string>
|
||||||
<string name="information_no_downloads">Δεν υπάρχουν λήψεις</string>
|
<string name="information_no_downloads">Δεν υπάρχουν λήψεις</string>
|
||||||
@ -308,7 +308,7 @@
|
|||||||
<string name="action_webview_refresh">Ανανέωση</string>
|
<string name="action_webview_refresh">Ανανέωση</string>
|
||||||
<string name="pref_category_library">Βιβλιοθήκη</string>
|
<string name="pref_category_library">Βιβλιοθήκη</string>
|
||||||
<string name="ext_obsolete">Απαρχαιωμένο</string>
|
<string name="ext_obsolete">Απαρχαιωμένο</string>
|
||||||
<string name="obsolete_extension_message">Αυτή η επέκταση δεν είναι πλέον διαθέσιμη.</string>
|
<string name="obsolete_extension_message">Αυτή η επέκταση δεν είναι πλέον διαθέσιμη. Ενδέχεται να μη λειτουργεί σωστά και μπορεί να προκαλέσει προβλήματα με την εφαρμογή. Συνιστάται η απεγκατάσταση της.</string>
|
||||||
<string name="label_more">Περισσότερα</string>
|
<string name="label_more">Περισσότερα</string>
|
||||||
<string name="last_used_source">Χρησιμοποιήθηκε τελευταία</string>
|
<string name="last_used_source">Χρησιμοποιήθηκε τελευταία</string>
|
||||||
<string name="add_tracking">Προσθήκη tracking</string>
|
<string name="add_tracking">Προσθήκη tracking</string>
|
||||||
@ -413,7 +413,7 @@
|
|||||||
<item quantity="one">Κεφάλαια %1$s και 1 ακόμη</item>
|
<item quantity="one">Κεφάλαια %1$s και 1 ακόμη</item>
|
||||||
<item quantity="other">Κεφάλαια %1$s και %2$d ακόμη</item>
|
<item quantity="other">Κεφάλαια %1$s και %2$d ακόμη</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="downloaded_only_summary">Φιλτράρει όλα τα manga στη βιβλιοθήκη σας</string>
|
<string name="downloaded_only_summary">Φιλτράρει όλες τις καταχωρήσεις στη βιβλιοθήκη σας</string>
|
||||||
<string name="pref_search_pinned_sources_only">Να περιέχονται μόνο καρφιτσωμένες πηγές</string>
|
<string name="pref_search_pinned_sources_only">Να περιέχονται μόνο καρφιτσωμένες πηγές</string>
|
||||||
<plurals name="download_queue_summary">
|
<plurals name="download_queue_summary">
|
||||||
<item quantity="one">%1$s που απομένει</item>
|
<item quantity="one">%1$s που απομένει</item>
|
||||||
@ -433,14 +433,14 @@
|
|||||||
<item quantity="other">Έγινε σε %1$s με %2$s σφάλματα</item>
|
<item quantity="other">Έγινε σε %1$s με %2$s σφάλματα</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="action_display_unread_badge">Μη αναγνωσμένα κεφάλαια</string>
|
<string name="action_display_unread_badge">Μη αναγνωσμένα κεφάλαια</string>
|
||||||
<string name="tracking_info">Μονόδρομος συγχρονισμός για ενημέρωση των υπηρεσιών παρακολούθησης προόδου κεφαλαίων. Ρυθμίστε την παρακολούθηση για μεμονωμένες καταχωρήσεις manga από το κουμπί παρακολούθησης τους.</string>
|
<string name="tracking_info">Μονόδρομος συγχρονισμός για ενημέρωση των υπηρεσιών παρακολούθησης προόδου κεφαλαίων. Ρυθμίστε την παρακολούθηση για μεμονωμένες καταχωρήσεις από το κουμπί παρακολούθησης τους.</string>
|
||||||
<string name="pref_refresh_library_covers">Ανανέωση εξώφυλλων βιβλιοθήκης</string>
|
<string name="pref_refresh_library_covers">Ανανέωση εξώφυλλων βιβλιοθήκης</string>
|
||||||
<string name="unofficial_extension_message">Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα επεκτάσεων Tachiyomi.</string>
|
<string name="unofficial_extension_message">Αυτή η επέκταση δεν προέρχεται από την επίσημη λίστα επεκτάσεων Tachiyomi.</string>
|
||||||
<string name="ext_unofficial">Ανεπίσημη</string>
|
<string name="ext_unofficial">Ανεπίσημη</string>
|
||||||
<string name="sort_by_upload_date">Από ημερομηνία μεταφόρτωσης</string>
|
<string name="sort_by_upload_date">Από ημερομηνία μεταφόρτωσης</string>
|
||||||
<string name="label_data">Δεδομένα</string>
|
<string name="label_data">Δεδομένα</string>
|
||||||
<string name="backup_restore_missing_sources">Πηγές που λείπουν:</string>
|
<string name="backup_restore_missing_sources">Πηγές που λείπουν:</string>
|
||||||
<string name="invalid_backup_file_missing_manga">Το αντίγραφο ασφαλείας δεν περιέχει manga.</string>
|
<string name="invalid_backup_file_missing_manga">Το αντίγραφο ασφαλείας δεν περιέχει καταχωρήσεις βιβλιοθήκης.</string>
|
||||||
<string name="invalid_backup_file">Μη έγκυρο αρχείο αντιγράφου ασφαλείας</string>
|
<string name="invalid_backup_file">Μη έγκυρο αρχείο αντιγράφου ασφαλείας</string>
|
||||||
<string name="pref_library_update_refresh_metadata_summary">Έλεγχος για νέο εξώφυλλο και λεπτομέρειες κατά την ενημέρωση της βιβλιοθήκης</string>
|
<string name="pref_library_update_refresh_metadata_summary">Έλεγχος για νέο εξώφυλλο και λεπτομέρειες κατά την ενημέρωση της βιβλιοθήκης</string>
|
||||||
<string name="pref_library_update_refresh_metadata">Αυτόματη ανανέωση μεταδεδομένων</string>
|
<string name="pref_library_update_refresh_metadata">Αυτόματη ανανέωση μεταδεδομένων</string>
|
||||||
@ -499,17 +499,17 @@
|
|||||||
<string name="no_chapters_error">Δεν βρέθηκαν κεφάλαια</string>
|
<string name="no_chapters_error">Δεν βρέθηκαν κεφάλαια</string>
|
||||||
<string name="chapter_settings_updated">Ενημερώθηκαν οι προεπιλεγμένες ρυθμίσεις κεφαλαίου</string>
|
<string name="chapter_settings_updated">Ενημερώθηκαν οι προεπιλεγμένες ρυθμίσεις κεφαλαίου</string>
|
||||||
<string name="set_chapter_settings_as_default">Ορισμός ως προεπιλογής</string>
|
<string name="set_chapter_settings_as_default">Ορισμός ως προεπιλογής</string>
|
||||||
<string name="also_set_chapter_settings_for_library">Εφαρμογή επίσης σε όλα τα manga στη βιβλιοθήκη μου</string>
|
<string name="also_set_chapter_settings_for_library">Εφαρμογή επίσης για όλες τις καταχωρήσεις στη βιβλιοθήκη μου</string>
|
||||||
<string name="confirm_set_chapter_settings">Είστε σίγουροι ότι θέλετε να αποθηκεύσετε αυτές τις ρυθμίσεις ως προεπιλεγμένες;</string>
|
<string name="confirm_set_chapter_settings">Είστε σίγουροι ότι θέλετε να αποθηκεύσετε αυτές τις ρυθμίσεις ως προεπιλεγμένες;</string>
|
||||||
<string name="chapter_settings">Ρυθμίσεις κεφαλαίου</string>
|
<string name="chapter_settings">Ρυθμίσεις κεφαλαίου</string>
|
||||||
<string name="share_page_info">%1$s: %2$s, σελίδα %3$d</string>
|
<string name="share_page_info">%1$s: %2$s, σελίδα %3$d</string>
|
||||||
<string name="action_search_settings">Αναζήτηση ρυθμίσεων</string>
|
<string name="action_search_settings">Αναζήτηση ρυθμίσεων</string>
|
||||||
<string name="downloaded_chapters">Κεφάλαια που έχουν ληφθεί</string>
|
<string name="downloaded_chapters">Κεφάλαια που έχουν ληφθεί</string>
|
||||||
<string name="manga_from_library">Manga από τη βιβλιοθήκη</string>
|
<string name="manga_from_library">Από βιβλιοθήκη</string>
|
||||||
<string name="pref_incognito_mode_summary">Παύει το ιστορικό ανάγνωσης</string>
|
<string name="pref_incognito_mode_summary">Παύει το ιστορικό ανάγνωσης</string>
|
||||||
<string name="pref_incognito_mode">Λειτουργία ανώνυμης περιήγησης</string>
|
<string name="pref_incognito_mode">Λειτουργία ανώνυμης περιήγησης</string>
|
||||||
<string name="pref_clear_history">Διαγραφή ιστορικού</string>
|
<string name="pref_clear_history">Διαγραφή ιστορικού</string>
|
||||||
<string name="clear_history_confirmation">Είστε σίγουροι\? Όλο το ιστορικό θα χαθεί.</string>
|
<string name="clear_history_confirmation">Είστε σίγουροι; Όλο το ιστορικό θα χαθεί.</string>
|
||||||
<string name="clear_history_completed">Το ιστορικό διαγράφηκε</string>
|
<string name="clear_history_completed">Το ιστορικό διαγράφηκε</string>
|
||||||
<string name="spen_next_page">Επόμενη σελίδα</string>
|
<string name="spen_next_page">Επόμενη σελίδα</string>
|
||||||
<string name="spen_previous_page">Προηγούμενη σελίδα</string>
|
<string name="spen_previous_page">Προηγούμενη σελίδα</string>
|
||||||
@ -552,15 +552,15 @@
|
|||||||
<string name="include">Συμπερίληψη: %s</string>
|
<string name="include">Συμπερίληψη: %s</string>
|
||||||
<string name="none">Κανένα</string>
|
<string name="none">Κανένα</string>
|
||||||
<string name="action_sort_chapter_fetch_date">Ημερομηνία ανάκτησης κεφαλαίου</string>
|
<string name="action_sort_chapter_fetch_date">Ημερομηνία ανάκτησης κεφαλαίου</string>
|
||||||
<string name="pref_download_new_categories_details">Τα Manga σε εξαιρούμενες κατηγορίες δεν θα ληφθούν ακόμα κι αν ανήκουν και σε κατηγορίες που περιλαμβάνονται.</string>
|
<string name="pref_download_new_categories_details">Οι καταχωρήσεις σε εξαιρούμενες κατηγορίες δε θα ληφθούν ακόμη και αν βρίσκονται επίσης σε κατηγορίες που περιλαμβάνονται.</string>
|
||||||
<string name="pref_category_auto_download">Αυτόματη λήψη</string>
|
<string name="pref_category_auto_download">Αυτόματη λήψη</string>
|
||||||
<string name="pref_library_update_categories_details">Τα manga στις αποκλεισμένες κατηγορίες δεν θα ενημερώνονται ακόμη και αν βρίσκονται επίσης στις συμπεριλαμβανόμενες κατηγορίες.</string>
|
<string name="pref_library_update_categories_details">Οι καταχωρίσεις σε εξαιρούμενες κατηγορίες δε θα ενημερώνονται ακόμη και αν περιλαμβάνονται επίσης σε κατηγορίες που περιλαμβάνονται.</string>
|
||||||
<string name="action_show_errors">Πατήστε για να δείτε λεπτομέρειες</string>
|
<string name="action_show_errors">Πατήστε για να δείτε λεπτομέρειες</string>
|
||||||
<string name="update_check_eol">Αυτή η έκδοση Android δεν υποστηρίζεται πλέον</string>
|
<string name="update_check_eol">Αυτή η έκδοση Android δεν υποστηρίζεται πλέον</string>
|
||||||
<string name="clipboard_copy_error">Απέτυχε η αντιγραφή στο πρόχειρο</string>
|
<string name="clipboard_copy_error">Απέτυχε η αντιγραφή στο πρόχειρο</string>
|
||||||
<string name="rotation_landscape">Οριζόντια</string>
|
<string name="rotation_landscape">Οριζόντια</string>
|
||||||
<string name="rotation_portrait">Κατακόρυφα</string>
|
<string name="rotation_portrait">Κατακόρυφα</string>
|
||||||
<string name="pref_create_folder_per_manga_summary">Δημιουργεί φακέλους σύμφωνα με τον τίτλο manga</string>
|
<string name="pref_create_folder_per_manga_summary">Δημιουργεί φακέλους σύμφωνα με τους τίτλους των καταχωρήσεων</string>
|
||||||
<string name="pref_create_folder_per_manga">Αποθήκευση σελίδων σε ξεχωριστούς φακέλους</string>
|
<string name="pref_create_folder_per_manga">Αποθήκευση σελίδων σε ξεχωριστούς φακέλους</string>
|
||||||
<string name="pref_reader_actions">Ενέργειες</string>
|
<string name="pref_reader_actions">Ενέργειες</string>
|
||||||
<string name="rotation_type">Τύπος περιστροφής</string>
|
<string name="rotation_type">Τύπος περιστροφής</string>
|
||||||
@ -578,7 +578,7 @@
|
|||||||
<string name="local_invalid_format">Μη έγκυρη μορφή κεφαλαίου</string>
|
<string name="local_invalid_format">Μη έγκυρη μορφή κεφαλαίου</string>
|
||||||
<string name="chapter_not_found">Το κεφάλαιο δε βρέθηκε</string>
|
<string name="chapter_not_found">Το κεφάλαιο δε βρέθηκε</string>
|
||||||
<string name="restrictions">Περιορισμοί: %s</string>
|
<string name="restrictions">Περιορισμοί: %s</string>
|
||||||
<string name="action_display_local_badge">Τοπικά manga</string>
|
<string name="action_display_local_badge">Τοπική πηγή</string>
|
||||||
<string name="off">Απενεργοποιημένο</string>
|
<string name="off">Απενεργοποιημένο</string>
|
||||||
<string name="on">Ενεργοποιημένο</string>
|
<string name="on">Ενεργοποιημένο</string>
|
||||||
<string name="error_sharing_cover">Σφάλμα κοινής χρήσης του εξωφύλλου</string>
|
<string name="error_sharing_cover">Σφάλμα κοινής χρήσης του εξωφύλλου</string>
|
||||||
@ -600,7 +600,7 @@
|
|||||||
<string name="theme_yinyang">Γιν και Γιανγκ</string>
|
<string name="theme_yinyang">Γιν και Γιανγκ</string>
|
||||||
<string name="theme_tako">Tako</string>
|
<string name="theme_tako">Tako</string>
|
||||||
<string name="theme_strawberrydaiquiri">Φράουλα Daiquiri</string>
|
<string name="theme_strawberrydaiquiri">Φράουλα Daiquiri</string>
|
||||||
<string name="enhanced_tracking_info">Υπηρεσίες που παρέχουν βελτιωμένες δυνατότητες για συγκεκριμένες πηγές. Τα manga παρακολουθούνται αυτόματα όταν προστίθεται στη βιβλιοθήκη σας.</string>
|
<string name="enhanced_tracking_info">Υπηρεσίες που παρέχουν βελτιωμένες δυνατότητες για συγκεκριμένες πηγές. Οι καταχωρήσεις παρακολουθούνται αυτόματα όταν προστίθενται στη βιβλιοθήκη σας.</string>
|
||||||
<string name="tracker_komga_warning">Αυτό το tracker είναι συμβατό μόνο με την πηγή Komga.</string>
|
<string name="tracker_komga_warning">Αυτό το tracker είναι συμβατό μόνο με την πηγή Komga.</string>
|
||||||
<string name="enhanced_services">Βελτιωμένες υπηρεσίες</string>
|
<string name="enhanced_services">Βελτιωμένες υπηρεσίες</string>
|
||||||
<string name="theme_monet">Δυναμικό</string>
|
<string name="theme_monet">Δυναμικό</string>
|
||||||
@ -636,7 +636,7 @@
|
|||||||
<string name="ext_installer_shizuku_unavailable_dialog">Εγκαταστήστε και ξεκινήστε το Shizuku για να χρησιμοποιήσετε το Shizuku ως πρόγραμμα εγκατάστασης επεκτάσεων.</string>
|
<string name="ext_installer_shizuku_unavailable_dialog">Εγκαταστήστε και ξεκινήστε το Shizuku για να χρησιμοποιήσετε το Shizuku ως πρόγραμμα εγκατάστασης επεκτάσεων.</string>
|
||||||
<string name="ext_installer_shizuku_stopped">Το Shizuku δεν τρέχει</string>
|
<string name="ext_installer_shizuku_stopped">Το Shizuku δεν τρέχει</string>
|
||||||
<string name="ext_installer_legacy">Παλαιό</string>
|
<string name="ext_installer_legacy">Παλαιό</string>
|
||||||
<string name="action_sort_count">Σύνολο manga</string>
|
<string name="action_sort_count">Σύνολο καταχωρήσεων</string>
|
||||||
<string name="pref_verbose_logging">Λεπτομερής καταγραφή</string>
|
<string name="pref_verbose_logging">Λεπτομερής καταγραφή</string>
|
||||||
<string name="pref_verbose_logging_summary">Εκτύπωση λεπτομερών αρχείων καταγραφής στο αρχείο καταγραφής συστήματος (μειώνει την απόδοση της εφαρμογής)</string>
|
<string name="pref_verbose_logging_summary">Εκτύπωση λεπτομερών αρχείων καταγραφής στο αρχείο καταγραφής συστήματος (μειώνει την απόδοση της εφαρμογής)</string>
|
||||||
<string name="action_display_language_badge">Γλώσσα</string>
|
<string name="action_display_language_badge">Γλώσσα</string>
|
||||||
@ -650,7 +650,7 @@
|
|||||||
<string name="ext_update_all">Ενημέρωση όλων</string>
|
<string name="ext_update_all">Ενημέρωση όλων</string>
|
||||||
<string name="channel_app_updates">Ενημερώσεις εφαρμογής</string>
|
<string name="channel_app_updates">Ενημερώσεις εφαρμογής</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Εκκαθάριση της προσωρινής μνήμης κεφαλαίων στο κλείσιμο της εφαρμογής</string>
|
<string name="pref_auto_clear_chapter_cache">Εκκαθάριση της προσωρινής μνήμης κεφαλαίων στο κλείσιμο της εφαρμογής</string>
|
||||||
<string name="clear_database_source_item_count">%1$d manga εκτός βιβλιοθήκης στη βάση δεδομένων</string>
|
<string name="clear_database_source_item_count">%1$d καταχωρήσεις εκτός βιβλιοθήκης στη βάση δεδομένων</string>
|
||||||
<string name="database_clean">Τίποτα προς εκκαθάριση</string>
|
<string name="database_clean">Τίποτα προς εκκαθάριση</string>
|
||||||
<string name="extension_api_error">Απέτυχε η λήψη λίστας επεκτάσεων</string>
|
<string name="extension_api_error">Απέτυχε η λήψη λίστας επεκτάσεων</string>
|
||||||
<string name="privacy_policy">Πολιτική απορρήτου</string>
|
<string name="privacy_policy">Πολιτική απορρήτου</string>
|
||||||
@ -663,7 +663,7 @@
|
|||||||
<string name="publishing_finished">Η έκδοσή ολοκληρώθηκε</string>
|
<string name="publishing_finished">Η έκδοσή ολοκληρώθηκε</string>
|
||||||
<string name="action_faq_and_guides">Συχνές ερωτήσεις και οδηγοί</string>
|
<string name="action_faq_and_guides">Συχνές ερωτήσεις και οδηγοί</string>
|
||||||
<string name="webtoon_side_padding_5">5%</string>
|
<string name="webtoon_side_padding_5">5%</string>
|
||||||
<string name="action_show_manga">Εμφάνιση manga</string>
|
<string name="action_show_manga">Εμφάνιση καταχώρισης</string>
|
||||||
<string name="pref_landscape_zoom">Ζουμ οριζόντιας εικόνας</string>
|
<string name="pref_landscape_zoom">Ζουμ οριζόντιας εικόνας</string>
|
||||||
<string name="confirm_manga_add_duplicate">Έχετε μια καταχώρηση στη βιβλιοθήκη σας με το ίδιο όνομα αλλά από διαφορετική πηγή (%1$s).
|
<string name="confirm_manga_add_duplicate">Έχετε μια καταχώρηση στη βιβλιοθήκη σας με το ίδιο όνομα αλλά από διαφορετική πηγή (%1$s).
|
||||||
\n
|
\n
|
||||||
@ -694,7 +694,7 @@
|
|||||||
<string name="battery_not_low">Όταν η μπαταρία δεν είναι χαμηλή</string>
|
<string name="battery_not_low">Όταν η μπαταρία δεν είναι χαμηλή</string>
|
||||||
<string name="source_filter_empty_screen">Δε βρέθηκε εγκατεστημένη πηγή</string>
|
<string name="source_filter_empty_screen">Δε βρέθηκε εγκατεστημένη πηγή</string>
|
||||||
<string name="action_sort_unread_count">Αριθμός μη αναγνωσμένων</string>
|
<string name="action_sort_unread_count">Αριθμός μη αναγνωσμένων</string>
|
||||||
<string name="action_sort_last_manga_update">Τελευταία ενημέρωση manga</string>
|
<string name="action_sort_last_manga_update">Τελευταίος έλεγχος ενημέρωσης</string>
|
||||||
<string name="source_empty_screen">Δε βρέθηκε πηγή</string>
|
<string name="source_empty_screen">Δε βρέθηκε πηγή</string>
|
||||||
<string name="split_tall_images">Διαχωρισμός ψηλών εικόνων</string>
|
<string name="split_tall_images">Διαχωρισμός ψηλών εικόνων</string>
|
||||||
<string name="split_tall_images_summary">Βελτιώνει την απόδοση του αναγνώστη</string>
|
<string name="split_tall_images_summary">Βελτιώνει την απόδοση του αναγνώστη</string>
|
||||||
@ -728,7 +728,7 @@
|
|||||||
<string name="pref_reset_user_agent_string">Επαναφορά προεπιλεγμένης συμβολοσειράς πράκτορα χρήστη</string>
|
<string name="pref_reset_user_agent_string">Επαναφορά προεπιλεγμένης συμβολοσειράς πράκτορα χρήστη</string>
|
||||||
<string name="action_remove_everything">Καταργήστε τα πάντα</string>
|
<string name="action_remove_everything">Καταργήστε τα πάντα</string>
|
||||||
<string name="loader_rar5_error">Η μορφή RARv5 δεν υποστηρίζεται</string>
|
<string name="loader_rar5_error">Η μορφή RARv5 δεν υποστηρίζεται</string>
|
||||||
<string name="appwidget_updates_description">Δείτε τα πρόσφατα ενημερωμένα manga σας</string>
|
<string name="appwidget_updates_description">Δείτε τις πρόσφατα ενημερωμένες καταχωρήσεις της βιβλιοθήκης σας</string>
|
||||||
<string name="appwidget_unavailable_locked">Το widget δεν είναι διαθέσιμο όταν είναι ενεργοποιημένο το κλείδωμα εφαρμογών</string>
|
<string name="appwidget_unavailable_locked">Το widget δεν είναι διαθέσιμο όταν είναι ενεργοποιημένο το κλείδωμα εφαρμογών</string>
|
||||||
<string name="update_already_running">Εκτελείται ήδη μια ενημέρωση</string>
|
<string name="update_already_running">Εκτελείται ήδη μια ενημέρωση</string>
|
||||||
<string name="error_user_agent_string_blank">Η συμβολοσειρά πράκτορα χρήστη δεν μπορεί να είναι κενή</string>
|
<string name="error_user_agent_string_blank">Η συμβολοσειρά πράκτορα χρήστη δεν μπορεί να είναι κενή</string>
|
||||||
@ -766,4 +766,10 @@
|
|||||||
<string name="invalid_location">Μη έγκυρη τοποθεσία: %s</string>
|
<string name="invalid_location">Μη έγκυρη τοποθεσία: %s</string>
|
||||||
<string name="error_user_agent_string_invalid">Μη έγκυρη συμβολοσειρά πράκτορα χρήστη</string>
|
<string name="error_user_agent_string_invalid">Μη έγκυρη συμβολοσειρά πράκτορα χρήστη</string>
|
||||||
<string name="updates_last_update_info_just_now">Μόλις τώρα</string>
|
<string name="updates_last_update_info_just_now">Μόλις τώρα</string>
|
||||||
|
<string name="download_notifier_cache_renewal">Λήψεις ευρετηρίου</string>
|
||||||
|
<string name="channel_downloader_cache">Προσωρινή μνήμη λήψεων</string>
|
||||||
|
<string name="fdroid_warning">Οι εκδόσεις F-Droid δεν υποστηρίζονται επίσημα.
|
||||||
|
\nΠατήστε για να μάθετε περισσότερα.</string>
|
||||||
|
<string name="action_open_random_manga">Άνοιγμα τυχαίας καταχώρησης</string>
|
||||||
|
<string name="information_no_entries_found">Δε βρέθηκαν καταχωρήσεις σε αυτή την κατηγορία</string>
|
||||||
</resources>
|
</resources>
|
@ -184,7 +184,7 @@
|
|||||||
<string name="update_check_look_for_updates">Buscando actualizaciones…</string>
|
<string name="update_check_look_for_updates">Buscando actualizaciones…</string>
|
||||||
<!--UpdateCheck Notifications-->
|
<!--UpdateCheck Notifications-->
|
||||||
<string name="update_check_notification_download_in_progress">Descargando…</string>
|
<string name="update_check_notification_download_in_progress">Descargando…</string>
|
||||||
<string name="update_check_notification_download_complete">Toca aquí para instalar</string>
|
<string name="update_check_notification_download_complete">Toca aquí para instalar la actualización</string>
|
||||||
<string name="update_check_notification_download_error">Error de descarga</string>
|
<string name="update_check_notification_download_error">Error de descarga</string>
|
||||||
<string name="update_check_notification_update_available">¡Nueva versión disponible!</string>
|
<string name="update_check_notification_update_available">¡Nueva versión disponible!</string>
|
||||||
<!--Content Description-->
|
<!--Content Description-->
|
||||||
@ -340,7 +340,7 @@
|
|||||||
<string name="action_webview_refresh">Actualizar</string>
|
<string name="action_webview_refresh">Actualizar</string>
|
||||||
<string name="pref_category_library">Biblioteca</string>
|
<string name="pref_category_library">Biblioteca</string>
|
||||||
<string name="ext_obsolete">Obsoleto</string>
|
<string name="ext_obsolete">Obsoleto</string>
|
||||||
<string name="obsolete_extension_message">Esta extensión ya no está disponible.</string>
|
<string name="obsolete_extension_message">Esta extensión ya no está disponible. Puede que no funcione bien y te cause problemas con el resto de la aplicación, te recomendamos desinstalarla.</string>
|
||||||
<string name="pref_date_format">Formato de fecha</string>
|
<string name="pref_date_format">Formato de fecha</string>
|
||||||
<string name="pref_category_library_update">Actualización global</string>
|
<string name="pref_category_library_update">Actualización global</string>
|
||||||
<string name="logout">Cerrar sesión</string>
|
<string name="logout">Cerrar sesión</string>
|
||||||
@ -810,4 +810,9 @@
|
|||||||
<string name="invalid_location">Ubicación incorrecta: %s</string>
|
<string name="invalid_location">Ubicación incorrecta: %s</string>
|
||||||
<string name="updates_last_update_info_just_now">Ahora mismo</string>
|
<string name="updates_last_update_info_just_now">Ahora mismo</string>
|
||||||
<string name="error_user_agent_string_invalid">El nombre de agente de usuario no vale</string>
|
<string name="error_user_agent_string_invalid">El nombre de agente de usuario no vale</string>
|
||||||
|
<string name="download_notifier_cache_renewal">Reindexando descargas</string>
|
||||||
|
<string name="channel_downloader_cache">Caché de descargas</string>
|
||||||
|
<string name="action_open_random_manga">Abrir manga al azar</string>
|
||||||
|
<string name="information_no_entries_found">No se ha encontrado ningún manga en esta categoría</string>
|
||||||
|
<string name="fdroid_warning">No damos soporte oficial a las versiones de F-Droid. Toca para más información.</string>
|
||||||
</resources>
|
</resources>
|
@ -672,4 +672,12 @@
|
|||||||
\n
|
\n
|
||||||
\nJarraitu nahi duzu\?</string>
|
\nJarraitu nahi duzu\?</string>
|
||||||
<string name="action_filter_started">Hasia</string>
|
<string name="action_filter_started">Hasia</string>
|
||||||
|
<string name="ext_info_version">Bertsioa</string>
|
||||||
|
<string name="multi_lang">Multi</string>
|
||||||
|
<string name="delete_category">Ezabatu kategoria</string>
|
||||||
|
<string name="action_close">Itxi</string>
|
||||||
|
<string name="pref_app_language">App hizkuntza</string>
|
||||||
|
<string name="battery_not_low">Bateria baxu ez dagoenean</string>
|
||||||
|
<string name="ext_info_language">Hizkuntza</string>
|
||||||
|
<string name="action_search_hint">Bilatu…</string>
|
||||||
</resources>
|
</resources>
|
@ -94,8 +94,8 @@
|
|||||||
<string name="label_recent_manga">Nakaraan</string>
|
<string name="label_recent_manga">Nakaraan</string>
|
||||||
<string name="label_recent_updates">Bago</string>
|
<string name="label_recent_updates">Bago</string>
|
||||||
<string name="label_library">Aklatan</string>
|
<string name="label_library">Aklatan</string>
|
||||||
<string name="label_download_queue">Dina-download</string>
|
<string name="label_download_queue">Mga Dina-download</string>
|
||||||
<string name="label_settings">Pagsasaayos</string>
|
<string name="label_settings">Mga Settings</string>
|
||||||
<string name="label_more">Higit pa</string>
|
<string name="label_more">Higit pa</string>
|
||||||
<string name="name">Pangalan</string>
|
<string name="name">Pangalan</string>
|
||||||
<plurals name="lock_after_mins">
|
<plurals name="lock_after_mins">
|
||||||
@ -105,7 +105,7 @@
|
|||||||
<string name="lock_never">Hindi</string>
|
<string name="lock_never">Hindi</string>
|
||||||
<string name="lock_always">Palagi</string>
|
<string name="lock_always">Palagi</string>
|
||||||
<string name="lock_when_idle">Isara kung nakatambay</string>
|
<string name="lock_when_idle">Isara kung nakatambay</string>
|
||||||
<string name="lock_with_biometrics">Kailangang i-unlock</string>
|
<string name="lock_with_biometrics">I-lock gamit ang biometrics</string>
|
||||||
<string name="pref_manage_notifications">Pamahalaan ang mga abiso</string>
|
<string name="pref_manage_notifications">Pamahalaan ang mga abiso</string>
|
||||||
<string name="pref_category_security">Seguridad</string>
|
<string name="pref_category_security">Seguridad</string>
|
||||||
<string name="pref_confirm_exit">Kumpirmahing aalis</string>
|
<string name="pref_confirm_exit">Kumpirmahing aalis</string>
|
||||||
@ -198,7 +198,7 @@
|
|||||||
<string name="pref_cutout_short">Ipakita ang laman sa cutout area</string>
|
<string name="pref_cutout_short">Ipakita ang laman sa cutout area</string>
|
||||||
<string name="pref_fullscreen">Naka-fullscreen</string>
|
<string name="pref_fullscreen">Naka-fullscreen</string>
|
||||||
<string name="unofficial_extension_message">Wala sa opisyal na listahan ng mga extension ng Tachiyomi ang extension na ito.</string>
|
<string name="unofficial_extension_message">Wala sa opisyal na listahan ng mga extension ng Tachiyomi ang extension na ito.</string>
|
||||||
<string name="obsolete_extension_message">Wala na\'ng ganitong extension.</string>
|
<string name="obsolete_extension_message">Hindi na available ang extension na ito. Maaaring hindi ito gumana nang maayos at maaaring magdulot ng mga isyu sa app. Inirerekomenda ang pag-uninstall nito.</string>
|
||||||
<string name="untrusted_extension_message">Pinirmahan ang extension na ito gamit ang isang kaduda-dudang certificate at hindi muna pinagana.
|
<string name="untrusted_extension_message">Pinirmahan ang extension na ito gamit ang isang kaduda-dudang certificate at hindi muna pinagana.
|
||||||
\n
|
\n
|
||||||
\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong credentials sa pag-login na nakatago sa Tachiyomi o di kaya nama\'y magsimula ng delikadong code.
|
\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong credentials sa pag-login na nakatago sa Tachiyomi o di kaya nama\'y magsimula ng delikadong code.
|
||||||
@ -246,7 +246,7 @@
|
|||||||
<string name="secure_screen">Bantayan ang screen</string>
|
<string name="secure_screen">Bantayan ang screen</string>
|
||||||
<string name="pref_read_with_tapping_inverted">Baligtarin ang mga tap zone</string>
|
<string name="pref_read_with_tapping_inverted">Baligtarin ang mga tap zone</string>
|
||||||
<string name="backup_restore_missing_sources">Nawawalang (mga) source:</string>
|
<string name="backup_restore_missing_sources">Nawawalang (mga) source:</string>
|
||||||
<string name="invalid_backup_file_missing_manga">Walang manga ang backup.</string>
|
<string name="invalid_backup_file_missing_manga">Ang backup ay hindi naglalaman ng anumang mga entry sa library.</string>
|
||||||
<string name="invalid_backup_file">Invalid na backup</string>
|
<string name="invalid_backup_file">Invalid na backup</string>
|
||||||
<string name="backup_created">Nai-backup na</string>
|
<string name="backup_created">Nai-backup na</string>
|
||||||
<string name="pref_backup_slots">Dami ng backup</string>
|
<string name="pref_backup_slots">Dami ng backup</string>
|
||||||
@ -259,7 +259,7 @@
|
|||||||
<string name="pref_create_backup">Mag-backup</string>
|
<string name="pref_create_backup">Mag-backup</string>
|
||||||
<string name="pref_search_pinned_sources_only">Isama lang ang mga naka-pin</string>
|
<string name="pref_search_pinned_sources_only">Isama lang ang mga naka-pin</string>
|
||||||
<string name="pref_enable_automatic_extension_updates">Tumingin ng mga update sa extension</string>
|
<string name="pref_enable_automatic_extension_updates">Tumingin ng mga update sa extension</string>
|
||||||
<string name="tracking_info">Isahang pagsabay para ma-update ang bilang ng nabasang kabanata sa mga tracker. Isaayos ang pag-track sa mga ito sa Pagta-track na makikita sa screen nila.</string>
|
<string name="tracking_info">One-way na pag-sync upang i-update ang pag-unlad ng kabanata sa mga serbisyo sa pagsubaybay. I-set up ang pagsubaybay para sa mga indibidwal na entry mula sa kanilang button sa pagsubaybay.</string>
|
||||||
<string name="services">Mga Serbisyo</string>
|
<string name="services">Mga Serbisyo</string>
|
||||||
<string name="pref_auto_update_manga_sync">I-update ang progress pagkabasa</string>
|
<string name="pref_auto_update_manga_sync">I-update ang progress pagkabasa</string>
|
||||||
<string name="pref_download_new">I-download ang mga bago</string>
|
<string name="pref_download_new">I-download ang mga bago</string>
|
||||||
@ -286,19 +286,19 @@
|
|||||||
<string name="information_webview_required">Kailangan ng Tachiyomi ang WebView</string>
|
<string name="information_webview_required">Kailangan ng Tachiyomi ang WebView</string>
|
||||||
<string name="information_cloudflare_bypass_failure">Bigong ma-bypass ang Cloudflare</string>
|
<string name="information_cloudflare_bypass_failure">Bigong ma-bypass ang Cloudflare</string>
|
||||||
<plurals name="update_check_notification_ext_updates">
|
<plurals name="update_check_notification_ext_updates">
|
||||||
<item quantity="one">Merong update sa extension</item>
|
<item quantity="one">Ang extension ay available upang i-update</item>
|
||||||
<item quantity="other">May %d (na) update sa extension</item>
|
<item quantity="other">Ang mga %d (na) extension ay available upang i-update</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="update_check_notification_update_available">May bagong bersyon!</string>
|
<string name="update_check_notification_update_available">May bagong bersyon!</string>
|
||||||
<string name="update_check_notification_download_error">Nagka-error sa pag-download</string>
|
<string name="update_check_notification_download_error">Nagka-error sa pag-download</string>
|
||||||
<string name="update_check_notification_download_complete">Pindutin para ma-install</string>
|
<string name="update_check_notification_download_complete">Pindutin upang ma-install ang update</string>
|
||||||
<string name="update_check_notification_download_in_progress">Dina-download…</string>
|
<string name="update_check_notification_download_in_progress">Dina-download…</string>
|
||||||
<string name="update_check_look_for_updates">Naghahanap ng mga update…</string>
|
<string name="update_check_look_for_updates">Naghahanap ng mga update…</string>
|
||||||
<string name="update_check_no_new_updates">Walang bagong update</string>
|
<string name="update_check_no_new_updates">Walang bagong update</string>
|
||||||
<string name="update_check_confirm">I-download</string>
|
<string name="update_check_confirm">I-download</string>
|
||||||
<string name="file_select_backup">Pumili ng backup</string>
|
<string name="file_select_backup">Pumili ng backup</string>
|
||||||
<string name="file_select_cover">Pumili ng cover</string>
|
<string name="file_select_cover">Pumili ng cover</string>
|
||||||
<string name="notification_first_add_to_library">Mangyaring idagdag muna ang manga sa Aklatan bago gawin ito</string>
|
<string name="notification_first_add_to_library">Maaaring ilagay ang entry sa iyong library bago ito gawin</string>
|
||||||
<string name="notification_cover_update_failed">Bigong mapalitan ang cover</string>
|
<string name="notification_cover_update_failed">Bigong mapalitan ang cover</string>
|
||||||
<plurals name="notification_chapters_multiple_and_more">
|
<plurals name="notification_chapters_multiple_and_more">
|
||||||
<item quantity="one">Mga kabanata %1$s at isa pa</item>
|
<item quantity="one">Mga kabanata %1$s at isa pa</item>
|
||||||
@ -345,7 +345,7 @@
|
|||||||
<string name="set_as_cover">Gawing cover</string>
|
<string name="set_as_cover">Gawing cover</string>
|
||||||
<string name="custom_filter">Pinili kong filter</string>
|
<string name="custom_filter">Pinili kong filter</string>
|
||||||
<string name="picture_saved">Na-save na ang larawan</string>
|
<string name="picture_saved">Na-save na ang larawan</string>
|
||||||
<string name="dialog_with_checkbox_reset">I-reset ang lahat ng kabanata ng manga na ito</string>
|
<string name="dialog_with_checkbox_reset">I-reset ang lahat ng chapters sa entry na ito</string>
|
||||||
<string name="dialog_with_checkbox_remove_description">Tatanggalin nito ang petsa ng pagbasa sa kabanatang ito. Sigurado ka ba\?</string>
|
<string name="dialog_with_checkbox_remove_description">Tatanggalin nito ang petsa ng pagbasa sa kabanatang ito. Sigurado ka ba\?</string>
|
||||||
<string name="snack_categories_deleted">Binura na ang mga kategorya</string>
|
<string name="snack_categories_deleted">Binura na ang mga kategorya</string>
|
||||||
<string name="error_category_exists">Mayroong kapangalan ang kategoryang ito!</string>
|
<string name="error_category_exists">Mayroong kapangalan ang kategoryang ito!</string>
|
||||||
@ -382,7 +382,7 @@
|
|||||||
<string name="chapter_error">Nagka-error</string>
|
<string name="chapter_error">Nagka-error</string>
|
||||||
<string name="chapter_downloading_progress">Dina-download (%1$d/%2$d)</string>
|
<string name="chapter_downloading_progress">Dina-download (%1$d/%2$d)</string>
|
||||||
<string name="display_mode_chapter">Kabanata %1$s</string>
|
<string name="display_mode_chapter">Kabanata %1$s</string>
|
||||||
<string name="snack_add_to_library">Idagdag ang manga sa Aklatan\?</string>
|
<string name="snack_add_to_library">Idagdag sa library\?</string>
|
||||||
<string name="source_not_installed">Di naka-install ang source: %1$s</string>
|
<string name="source_not_installed">Di naka-install ang source: %1$s</string>
|
||||||
<string name="copied_to_clipboard">Kinopya sa clipboard:
|
<string name="copied_to_clipboard">Kinopya sa clipboard:
|
||||||
\n%1$s</string>
|
\n%1$s</string>
|
||||||
@ -431,9 +431,9 @@
|
|||||||
<string name="login_title">Mag-login sa %1$s</string>
|
<string name="login_title">Mag-login sa %1$s</string>
|
||||||
<plurals name="download_queue_summary">
|
<plurals name="download_queue_summary">
|
||||||
<item quantity="one">%1$s na lang</item>
|
<item quantity="one">%1$s na lang</item>
|
||||||
<item quantity="other">%1$s na lang</item>
|
<item quantity="other">%1$s pa ang nasa queue</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="downloaded_only_summary">I-filter ang lahat ng manga sa Aklatan</string>
|
<string name="downloaded_only_summary">I-filter ang lahat ng mga entry sa iyong library</string>
|
||||||
<string name="label_downloaded_only">Mga na-download lang</string>
|
<string name="label_downloaded_only">Mga na-download lang</string>
|
||||||
<string name="pref_acra_summary">Nakatutulong sa pag-ayos sa mga bug. Walang sensitibong data ang ipapadala</string>
|
<string name="pref_acra_summary">Nakatutulong sa pag-ayos sa mga bug. Walang sensitibong data ang ipapadala</string>
|
||||||
<string name="pref_enable_acra">Ipadala ang mga ulat ng pag-crash</string>
|
<string name="pref_enable_acra">Ipadala ang mga ulat ng pag-crash</string>
|
||||||
@ -451,8 +451,8 @@
|
|||||||
<string name="pref_refresh_library_tracking">Sariwain ang pagta-track</string>
|
<string name="pref_refresh_library_tracking">Sariwain ang pagta-track</string>
|
||||||
<string name="pref_refresh_library_covers">Sariwain ang mga cover sa Aklatan</string>
|
<string name="pref_refresh_library_covers">Sariwain ang mga cover sa Aklatan</string>
|
||||||
<string name="clear_database_completed">Binura na</string>
|
<string name="clear_database_completed">Binura na</string>
|
||||||
<string name="clear_database_confirmation">Sigurado ka ba talaga\? Mawawala ang lahat ng mga nabasang kabanata at bahagdang nabasa ng mga manga na wala sa Aklatan</string>
|
<string name="clear_database_confirmation">Sigurado ka ba\? Mga basa na chapters at mga progress sa mga entry ng non-library ay mawawala</string>
|
||||||
<string name="pref_clear_database_summary">Burahin ang nakaraan ng mga manga na hindi nakalagay sa Aklatan mo</string>
|
<string name="pref_clear_database_summary">Burahin ang history para sa mga entry na hindi naka-save sa iyong library</string>
|
||||||
<string name="pref_clear_database">Linisin ang database</string>
|
<string name="pref_clear_database">Linisin ang database</string>
|
||||||
<string name="cache_delete_error">Nagka-error habang nililinis</string>
|
<string name="cache_delete_error">Nagka-error habang nililinis</string>
|
||||||
<string name="cache_deleted">Nalinis na ang cache. Binura ang %1$d (na) file</string>
|
<string name="cache_deleted">Nalinis na ang cache. Binura ang %1$d (na) file</string>
|
||||||
@ -493,18 +493,18 @@
|
|||||||
<string name="ext_nsfw_warning">Posibleng may NSFW (18+) content ang mga source mula sa extension na ito</string>
|
<string name="ext_nsfw_warning">Posibleng may NSFW (18+) content ang mga source mula sa extension na ito</string>
|
||||||
<string name="ext_nsfw_short">18+</string>
|
<string name="ext_nsfw_short">18+</string>
|
||||||
<plurals name="missing_chapters_warning">
|
<plurals name="missing_chapters_warning">
|
||||||
<item quantity="one">Lalaktawan ang %d kabanata, siguro baka wala sa source ito, o baka na-filter ito</item>
|
<item quantity="one">Nilaktawan ang %d na chapter, maaaring wala ang pinagmulan nito o na-filter na ito</item>
|
||||||
<item quantity="other">Lalaktawan ang %d (na) kabanata, siguro baka sa source ang mga ito, o baka na-filter sila</item>
|
<item quantity="other">Lalaktawan ang %d na mga chapter, maaaring wala ang pinagmulan nito o na-filter na ito</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="no_chapters_error">Walang nakitang kabanata</string>
|
<string name="no_chapters_error">Walang nakitang kabanata</string>
|
||||||
<string name="confirm_set_chapter_settings">Gusto mo bang i-save at ipagpaubaya ang pagsasaayos na ito\?</string>
|
<string name="confirm_set_chapter_settings">Gusto mo bang i-save at ipagpaubaya ang pagsasaayos na ito\?</string>
|
||||||
<string name="set_chapter_settings_as_default">Ipagpaubaya</string>
|
<string name="set_chapter_settings_as_default">Ipagpaubaya</string>
|
||||||
<string name="chapter_settings_updated">Ini-update na ang Ipagpaubaya</string>
|
<string name="chapter_settings_updated">Ini-update na ang Ipagpaubaya</string>
|
||||||
<string name="share_page_info">%1$s: %2$s, pahina %3$d</string>
|
<string name="share_page_info">%1$s: %2$s, pahina %3$d</string>
|
||||||
<string name="also_set_chapter_settings_for_library">Gawin din sa lahat ng mga manga sa Aklatan ko</string>
|
<string name="also_set_chapter_settings_for_library">Gawin din sa lahat ng mga entry sa aking library</string>
|
||||||
<string name="chapter_settings">Pagsasaayos ng Kabanata</string>
|
<string name="chapter_settings">Pagsasaayos ng Kabanata</string>
|
||||||
<string name="downloaded_chapters">Mga naka-download na kabanata</string>
|
<string name="downloaded_chapters">Mga naka-download na kabanata</string>
|
||||||
<string name="manga_from_library">Manga mula sa Aklatan</string>
|
<string name="manga_from_library">Galing sa library</string>
|
||||||
<string name="action_search_settings">Maghanap</string>
|
<string name="action_search_settings">Maghanap</string>
|
||||||
<string name="pref_incognito_mode_summary">Hinihinto ang pagtala sa nakaraan</string>
|
<string name="pref_incognito_mode_summary">Hinihinto ang pagtala sa nakaraan</string>
|
||||||
<string name="pref_incognito_mode">Nakatago</string>
|
<string name="pref_incognito_mode">Nakatago</string>
|
||||||
@ -542,7 +542,7 @@
|
|||||||
\n
|
\n
|
||||||
\nKailangan mong i-install muli ang mga nawawalang extension at mag-login muli sa mga tracker pagkatapos para magamit ang mga ito.</string>
|
\nKailangan mong i-install muli ang mga nawawalang extension at mag-login muli sa mga tracker pagkatapos para magamit ang mga ito.</string>
|
||||||
<string name="pref_dns_over_https">DNS kesa HTTPS (DoH)</string>
|
<string name="pref_dns_over_https">DNS kesa HTTPS (DoH)</string>
|
||||||
<string name="pref_download_new_categories_details">Hindi ida-download ang mga manga na nasa di-kasamang kategorya kahit na nasa kasamang kategorya ang mga ito.</string>
|
<string name="pref_download_new_categories_details">Ang mga entry sa mga ibinukod na kategorya ay hindi mada-download kahit na sila ay kasama rin sa mga kategoryang kasama.</string>
|
||||||
<string name="pref_category_auto_download">Kusang pag-download</string>
|
<string name="pref_category_auto_download">Kusang pag-download</string>
|
||||||
<string name="nav_zone_right">Kanan</string>
|
<string name="nav_zone_right">Kanan</string>
|
||||||
<string name="nav_zone_left">Kaliwa</string>
|
<string name="nav_zone_left">Kaliwa</string>
|
||||||
@ -553,7 +553,7 @@
|
|||||||
<string name="exclude">Di-kasama: %s</string>
|
<string name="exclude">Di-kasama: %s</string>
|
||||||
<string name="include">Kasama: %s</string>
|
<string name="include">Kasama: %s</string>
|
||||||
<string name="none">Wala</string>
|
<string name="none">Wala</string>
|
||||||
<string name="pref_library_update_categories_details">Di ia-update ang mga manga na nasa mga kategoryang di-kasama kahit na nasa kasamang kategorya rin ito.</string>
|
<string name="pref_library_update_categories_details">Ang mga entry sa mga ibinukod na kategorya ay hindi maa-update kahit na sila ay kasama rin sa mga kategoryang kasama.</string>
|
||||||
<string name="action_sort_chapter_fetch_date">Petsa kinuha</string>
|
<string name="action_sort_chapter_fetch_date">Petsa kinuha</string>
|
||||||
<string name="action_show_errors">Pindutin para makita ang detalye</string>
|
<string name="action_show_errors">Pindutin para makita ang detalye</string>
|
||||||
<string name="update_check_eol">Di na suportado ang bersyong ito ng Android</string>
|
<string name="update_check_eol">Di na suportado ang bersyong ito ng Android</string>
|
||||||
@ -584,7 +584,7 @@
|
|||||||
<string name="manga_cover">Cover</string>
|
<string name="manga_cover">Cover</string>
|
||||||
<string name="off">Patayin</string>
|
<string name="off">Patayin</string>
|
||||||
<string name="on">Buksan</string>
|
<string name="on">Buksan</string>
|
||||||
<string name="action_display_local_badge">Lokal na manga</string>
|
<string name="action_display_local_badge">Lokal na pinanggagalingan</string>
|
||||||
<string name="categorized_display_settings">Pagpapakita kada kategorya</string>
|
<string name="categorized_display_settings">Pagpapakita kada kategorya</string>
|
||||||
<string name="information_empty_category_dialog">Wala ka pang kategorya.</string>
|
<string name="information_empty_category_dialog">Wala ka pang kategorya.</string>
|
||||||
<string name="tracking_guide">Gabay sa pag-track</string>
|
<string name="tracking_guide">Gabay sa pag-track</string>
|
||||||
@ -593,7 +593,7 @@
|
|||||||
<string name="tracker_komga_warning">Gumagana lang ang tracker na ito gamit ang source ng Komga.</string>
|
<string name="tracker_komga_warning">Gumagana lang ang tracker na ito gamit ang source ng Komga.</string>
|
||||||
<string name="about_dont_kill_my_app">May dagdag na mga restriksyon sa app ang ilang mga modelo ng phone na pumapatay sa mga serbisyong nasa likuran. May impormasyon sa site na ito para maayos ang naturang problema.</string>
|
<string name="about_dont_kill_my_app">May dagdag na mga restriksyon sa app ang ilang mga modelo ng phone na pumapatay sa mga serbisyong nasa likuran. May impormasyon sa site na ito para maayos ang naturang problema.</string>
|
||||||
<string name="restore_miui_warning">Maaaring hindi gumana nang maayos ang pag-backup/pag-restore kung nakasara ang MIUI optimization.</string>
|
<string name="restore_miui_warning">Maaaring hindi gumana nang maayos ang pag-backup/pag-restore kung nakasara ang MIUI optimization.</string>
|
||||||
<string name="enhanced_tracking_info">Mga serbisyong nagbibigay ng pinahusay na tampok para sa mga piling source. Kusang ita-track ang manga kapag dinagdag ito sa Aklatan mo.</string>
|
<string name="enhanced_tracking_info">Mga serbisyong nagbibigay ng mga pinahusay na feature para sa mga partikular na source. Awtomatikong sinusubaybayan ang mga entry kapag idinagdag sa iyong library.</string>
|
||||||
<string name="enhanced_services">Pinahusay na serbisyo</string>
|
<string name="enhanced_services">Pinahusay na serbisyo</string>
|
||||||
<string name="theme_midnightdusk">Hatinggabi</string>
|
<string name="theme_midnightdusk">Hatinggabi</string>
|
||||||
<string name="theme_greenapple">Berdeng Mansanas</string>
|
<string name="theme_greenapple">Berdeng Mansanas</string>
|
||||||
@ -616,7 +616,7 @@
|
|||||||
<string name="pref_relative_format">Pagpepetsa</string>
|
<string name="pref_relative_format">Pagpepetsa</string>
|
||||||
<plurals name="relative_time">
|
<plurals name="relative_time">
|
||||||
<item quantity="one">Kahapon</item>
|
<item quantity="one">Kahapon</item>
|
||||||
<item quantity="other">%1$d (na) araw ang nakalipas</item>
|
<item quantity="other">%1$d na mga araw ang lumipas</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="recently">Kamakailan</string>
|
<string name="recently">Kamakailan</string>
|
||||||
<string name="relative_time_today">Ngayon</string>
|
<string name="relative_time_today">Ngayon</string>
|
||||||
@ -636,7 +636,7 @@
|
|||||||
<string name="ext_installer_legacy">Legasiya</string>
|
<string name="ext_installer_legacy">Legasiya</string>
|
||||||
<string name="ext_installer_pref">Taga-install</string>
|
<string name="ext_installer_pref">Taga-install</string>
|
||||||
<string name="ext_install_service_notif">Ini-install ang extension…</string>
|
<string name="ext_install_service_notif">Ini-install ang extension…</string>
|
||||||
<string name="action_sort_count">Dami ng manga</string>
|
<string name="action_sort_count">Dami ng mga entry</string>
|
||||||
<string name="pref_verbose_logging">Verbose na pagla-log</string>
|
<string name="pref_verbose_logging">Verbose na pagla-log</string>
|
||||||
<string name="pref_verbose_logging_summary">Mag-print ng mga verbose na log sa log ng sistema (dagdag-pasanin sa app)</string>
|
<string name="pref_verbose_logging_summary">Mag-print ng mga verbose na log sa log ng sistema (dagdag-pasanin sa app)</string>
|
||||||
<string name="notification_size_warning">Babala: Nakasasama ang mga malalaking update sa source at maaaring humantong sa mabagal na update at pagtaas ng paggamit sa baterya. Pindutin para matuto pa.</string>
|
<string name="notification_size_warning">Babala: Nakasasama ang mga malalaking update sa source at maaaring humantong sa mabagal na update at pagtaas ng paggamit sa baterya. Pindutin para matuto pa.</string>
|
||||||
@ -649,7 +649,7 @@
|
|||||||
<string name="pref_library_update_show_tab_badge">Ipakita ang bilang ng di pa nabasa sa Bago</string>
|
<string name="pref_library_update_show_tab_badge">Ipakita ang bilang ng di pa nabasa sa Bago</string>
|
||||||
<string name="channel_app_updates">Mga update sa app</string>
|
<string name="channel_app_updates">Mga update sa app</string>
|
||||||
<string name="ext_update_all">I-update lahat</string>
|
<string name="ext_update_all">I-update lahat</string>
|
||||||
<string name="clear_database_source_item_count">May %1$d (na) manga sa database na wala sa Aklatan</string>
|
<string name="clear_database_source_item_count">May %1$d na mga entry na non-library sa database</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Linisin ang cache ng kabanata pagkasara</string>
|
<string name="pref_auto_clear_chapter_cache">Linisin ang cache ng kabanata pagkasara</string>
|
||||||
<string name="database_clean">Walang malilinis</string>
|
<string name="database_clean">Walang malilinis</string>
|
||||||
<string name="extension_api_error">Bigong makuha ang mga extension</string>
|
<string name="extension_api_error">Bigong makuha ang mga extension</string>
|
||||||
@ -663,7 +663,7 @@
|
|||||||
<string name="cancelled">Kinansela</string>
|
<string name="cancelled">Kinansela</string>
|
||||||
<string name="action_faq_and_guides">Mga Madalas Itanong at Gabay</string>
|
<string name="action_faq_and_guides">Mga Madalas Itanong at Gabay</string>
|
||||||
<string name="webtoon_side_padding_5">5%</string>
|
<string name="webtoon_side_padding_5">5%</string>
|
||||||
<string name="action_show_manga">Ipakita ang manga</string>
|
<string name="action_show_manga">Ipakita ang mga entry</string>
|
||||||
<string name="action_filter_started">Nasimulan</string>
|
<string name="action_filter_started">Nasimulan</string>
|
||||||
<string name="action_display_cover_only_grid">Pabalat lang</string>
|
<string name="action_display_cover_only_grid">Pabalat lang</string>
|
||||||
<string name="skipped_reason_completed">Nilaktawan dahil tapos na ang serye</string>
|
<string name="skipped_reason_completed">Nilaktawan dahil tapos na ang serye</string>
|
||||||
@ -694,7 +694,7 @@
|
|||||||
<string name="pref_duplicate_pinned_sources_summary">Ulitin ang pag-pin sa mga source sa kani-kanilang mga wika</string>
|
<string name="pref_duplicate_pinned_sources_summary">Ulitin ang pag-pin sa mga source sa kani-kanilang mga wika</string>
|
||||||
<string name="source_filter_empty_screen">Walang nakitang naka-install na source</string>
|
<string name="source_filter_empty_screen">Walang nakitang naka-install na source</string>
|
||||||
<string name="source_empty_screen">Walang nakitang source</string>
|
<string name="source_empty_screen">Walang nakitang source</string>
|
||||||
<string name="action_sort_last_manga_update">Huling update sa manga</string>
|
<string name="action_sort_last_manga_update">Huling update ng pag-tsek</string>
|
||||||
<string name="action_sort_unread_count">Dami ng di pa nabasa</string>
|
<string name="action_sort_unread_count">Dami ng di pa nabasa</string>
|
||||||
<string name="split_tall_images">Hatiin ang mga matatangkad na larawan</string>
|
<string name="split_tall_images">Hatiin ang mga matatangkad na larawan</string>
|
||||||
<string name="split_tall_images_summary">Pinapahusay ang performance ng reader</string>
|
<string name="split_tall_images_summary">Pinapahusay ang performance ng reader</string>
|
||||||
@ -728,7 +728,7 @@
|
|||||||
<string name="pref_user_agent_string">Default na string ng user agent</string>
|
<string name="pref_user_agent_string">Default na string ng user agent</string>
|
||||||
<string name="action_remove_everything">Burahin lahat</string>
|
<string name="action_remove_everything">Burahin lahat</string>
|
||||||
<string name="loader_rar5_error">Di suportado ang format na RARv5</string>
|
<string name="loader_rar5_error">Di suportado ang format na RARv5</string>
|
||||||
<string name="appwidget_updates_description">Tingnan ang mga kamakailang na-update na manga mo</string>
|
<string name="appwidget_updates_description">Tingnan ang iyong kamakailang na-update na mga entry sa library</string>
|
||||||
<string name="appwidget_unavailable_locked">Di available ang widget kapag nakabukas ang lock</string>
|
<string name="appwidget_unavailable_locked">Di available ang widget kapag nakabukas ang lock</string>
|
||||||
<string name="update_already_running">May ina-update sa ngayon</string>
|
<string name="update_already_running">May ina-update sa ngayon</string>
|
||||||
<string name="error_user_agent_string_blank">Hindi dapat blangko ang user agent string</string>
|
<string name="error_user_agent_string_blank">Hindi dapat blangko ang user agent string</string>
|
||||||
@ -738,12 +738,12 @@
|
|||||||
<string name="download_ahead_info">Gagana lang sa mga entry sa aklatan at kung naka-download na ang kasalukuyang kabanata pati ang susunod</string>
|
<string name="download_ahead_info">Gagana lang sa mga entry sa aklatan at kung naka-download na ang kasalukuyang kabanata pati ang susunod</string>
|
||||||
<string name="are_you_sure">Sigurado ka ba\?</string>
|
<string name="are_you_sure">Sigurado ka ba\?</string>
|
||||||
<plurals name="next_unread_chapters">
|
<plurals name="next_unread_chapters">
|
||||||
<item quantity="one">Susunod na kabanatang di pa nabasa</item>
|
<item quantity="one">Susunod ang hindi pa nababasa na chapter</item>
|
||||||
<item quantity="other">Susunod na %d (na) kabanatang di pa nabasa</item>
|
<item quantity="other">Susunod ang mga %d na hindi pa nababasa na mga chapter</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="multi_lang">Marami</string>
|
<string name="multi_lang">Marami</string>
|
||||||
<string name="remove_manga">Tatanggalin mo na ang \"%s\" mula sa iyong aklatan</string>
|
<string name="remove_manga">Tatanggalin mo na ang \"%s\" mula sa iyong aklatan</string>
|
||||||
<string name="updates_last_update_info">Huling na-update ang Aklatan noong: %1$s</string>
|
<string name="updates_last_update_info">Huling update ng Library: %s</string>
|
||||||
<string name="pref_long_strip_split">Hatiin ang mga matatangkad na larawan (BETA)</string>
|
<string name="pref_long_strip_split">Hatiin ang mga matatangkad na larawan (BETA)</string>
|
||||||
<string name="popular">Sikat</string>
|
<string name="popular">Sikat</string>
|
||||||
<string name="missing_storage_permission">Hindi binigay ang mga permiso sa storage</string>
|
<string name="missing_storage_permission">Hindi binigay ang mga permiso sa storage</string>
|
||||||
@ -763,7 +763,13 @@
|
|||||||
<string name="pref_general_summary">Wika ng App, mga abiso</string>
|
<string name="pref_general_summary">Wika ng App, mga abiso</string>
|
||||||
<string name="crash_screen_restart_application">Buksan muli ang app</string>
|
<string name="crash_screen_restart_application">Buksan muli ang app</string>
|
||||||
<string name="invalid_location">Hindi wastong lokasyon: %s</string>
|
<string name="invalid_location">Hindi wastong lokasyon: %s</string>
|
||||||
<string name="unknown_title">Di tiyak na pamagat</string>
|
<string name="unknown_title">Hindi alam ang Pamagat</string>
|
||||||
<string name="error_user_agent_string_invalid">Hindi wastong user agent</string>
|
<string name="error_user_agent_string_invalid">Hindi wasto ang string ng user agent</string>
|
||||||
<string name="updates_last_update_info_just_now">Ngayon lang</string>
|
<string name="updates_last_update_info_just_now">Ngayon lang</string>
|
||||||
|
<string name="download_notifier_cache_renewal">Pag-index ng mga pag-download</string>
|
||||||
|
<string name="channel_downloader_cache">Cache ng mga download</string>
|
||||||
|
<string name="information_no_entries_found">Walang mga entry ang nahanap sa kategoryang ito</string>
|
||||||
|
<string name="action_open_random_manga">Buksan ang random na entry</string>
|
||||||
|
<string name="fdroid_warning">Ang mga build ng F-Droid ay hindi opisyal na sinusuportahan.
|
||||||
|
\nI-tap para matuto pa.</string>
|
||||||
</resources>
|
</resources>
|
@ -376,7 +376,7 @@
|
|||||||
<string name="pref_library_columns">פריטים לשורה</string>
|
<string name="pref_library_columns">פריטים לשורה</string>
|
||||||
<string name="theme_system">עקוב אחר המערכת</string>
|
<string name="theme_system">עקוב אחר המערכת</string>
|
||||||
<string name="pref_library_update_refresh_metadata_summary">בדוק אם יש כריכה ופרטים חדשים בעת עדכון הספרייה</string>
|
<string name="pref_library_update_refresh_metadata_summary">בדוק אם יש כריכה ופרטים חדשים בעת עדכון הספרייה</string>
|
||||||
<string name="action_sort_count">סה\"כ מאנגה</string>
|
<string name="action_sort_count">סה\"כ פריטים</string>
|
||||||
<string name="action_search_settings">הגדרות חיפוש</string>
|
<string name="action_search_settings">הגדרות חיפוש</string>
|
||||||
<string name="action_select_inverse">בחר את ההפך</string>
|
<string name="action_select_inverse">בחר את ההפך</string>
|
||||||
<string name="action_display_language_badge">שפה</string>
|
<string name="action_display_language_badge">שפה</string>
|
||||||
@ -408,7 +408,7 @@
|
|||||||
<string name="action_migrate">העברה</string>
|
<string name="action_migrate">העברה</string>
|
||||||
<string name="action_display_comfortable_grid">רשת נוחה</string>
|
<string name="action_display_comfortable_grid">רשת נוחה</string>
|
||||||
<string name="action_display_unread_badge">פרקים שלא נקראו</string>
|
<string name="action_display_unread_badge">פרקים שלא נקראו</string>
|
||||||
<string name="action_display_local_badge">מנגה מקומית</string>
|
<string name="action_display_local_badge">מקור מקומי</string>
|
||||||
<string name="theme_tealturquoise">טורקיז צהבהב</string>
|
<string name="theme_tealturquoise">טורקיז צהבהב</string>
|
||||||
<string name="pref_dark_theme_pure_black">מצב שחור כהה טהור</string>
|
<string name="pref_dark_theme_pure_black">מצב שחור כהה טהור</string>
|
||||||
<string name="theme_greenapple">ירוק תפוח</string>
|
<string name="theme_greenapple">ירוק תפוח</string>
|
||||||
@ -425,7 +425,7 @@
|
|||||||
<string name="action_sort_chapter_fetch_date">תאריך האחזור של הפרקים</string>
|
<string name="action_sort_chapter_fetch_date">תאריך האחזור של הפרקים</string>
|
||||||
<string name="theme_monet">דינמי</string>
|
<string name="theme_monet">דינמי</string>
|
||||||
<string name="pref_library_update_categories_details">מנגה הנמצאת בקטגוריית מנועי העדכונים לא תעודכן גם אם היא נכללת בקטגורייה אחרת שכן מתעדכנת.</string>
|
<string name="pref_library_update_categories_details">מנגה הנמצאת בקטגוריית מנועי העדכונים לא תעודכן גם אם היא נכללת בקטגורייה אחרת שכן מתעדכנת.</string>
|
||||||
<string name="action_show_manga">הראה מנגה</string>
|
<string name="action_show_manga">הראה פריט</string>
|
||||||
<string name="action_filter_started">התחיל</string>
|
<string name="action_filter_started">התחיל</string>
|
||||||
<string name="pref_update_only_completely_read">עם פרק(ים) שלא נקרא(ו)</string>
|
<string name="pref_update_only_completely_read">עם פרק(ים) שלא נקרא(ו)</string>
|
||||||
<string name="action_move_to_top_all_for_series">העבר סדרה לראש</string>
|
<string name="action_move_to_top_all_for_series">העבר סדרה לראש</string>
|
||||||
@ -626,7 +626,7 @@
|
|||||||
<string name="learn_more">לחץ כדי ללמוד עוד</string>
|
<string name="learn_more">לחץ כדי ללמוד עוד</string>
|
||||||
<string name="pref_clear_history">נקה היסטוריה</string>
|
<string name="pref_clear_history">נקה היסטוריה</string>
|
||||||
<string name="pref_reset_viewer_flags_error">נכשל איפוס הגדרות מצב הקריאה</string>
|
<string name="pref_reset_viewer_flags_error">נכשל איפוס הגדרות מצב הקריאה</string>
|
||||||
<string name="action_sort_last_manga_update">עדכון המנגה האחרון</string>
|
<string name="action_sort_last_manga_update">עדכון אחרון</string>
|
||||||
<string name="action_sort_unread_count">לא נקראו</string>
|
<string name="action_sort_unread_count">לא נקראו</string>
|
||||||
<string name="battery_not_low">אין קצת סוללה</string>
|
<string name="battery_not_low">אין קצת סוללה</string>
|
||||||
<string name="categorized_display_settings">הגדרות מיון ותצוגה לכל קטגוריה בנפרד</string>
|
<string name="categorized_display_settings">הגדרות מיון ותצוגה לכל קטגוריה בנפרד</string>
|
||||||
@ -685,4 +685,8 @@
|
|||||||
<string name="pref_dual_page_invert_summary">אם המקום של הפיצול עמוד לא תואם לכיוון הקריאה</string>
|
<string name="pref_dual_page_invert_summary">אם המקום של הפיצול עמוד לא תואם לכיוון הקריאה</string>
|
||||||
<string name="tapping_inverted_none">כלום</string>
|
<string name="tapping_inverted_none">כלום</string>
|
||||||
<string name="pref_viewer_nav">איזורי נגיעה</string>
|
<string name="pref_viewer_nav">איזורי נגיעה</string>
|
||||||
|
<string name="loader_rar5_error">הפורמט RARv5 לא נתמך</string>
|
||||||
|
<string name="action_search_hint">חיפוש…</string>
|
||||||
|
<string name="action_open_random_manga">פתיחת פריט אקראי</string>
|
||||||
|
<string name="getting_started_guide">מדריך למתחיל</string>
|
||||||
</resources>
|
</resources>
|
@ -523,7 +523,7 @@
|
|||||||
<string name="action_display_show_number_of_items">Tampilkan jumlah item</string>
|
<string name="action_display_show_number_of_items">Tampilkan jumlah item</string>
|
||||||
<string name="none">Kosong</string>
|
<string name="none">Kosong</string>
|
||||||
<string name="action_show_errors">Ketuk untuk melihat detail</string>
|
<string name="action_show_errors">Ketuk untuk melihat detail</string>
|
||||||
<string name="action_sort_chapter_fetch_date">Tanggal pengambilan bab</string>
|
<string name="action_sort_chapter_fetch_date">Tanggal bab dimasukkan</string>
|
||||||
<string name="pref_reader_actions">Aksi</string>
|
<string name="pref_reader_actions">Aksi</string>
|
||||||
<string name="nav_zone_right">Kanan</string>
|
<string name="nav_zone_right">Kanan</string>
|
||||||
<string name="nav_zone_left">Kiri</string>
|
<string name="nav_zone_left">Kiri</string>
|
||||||
@ -682,7 +682,7 @@
|
|||||||
<string name="pref_duplicate_pinned_sources_summary">Ulang sumber ditandai pada kelompok bahasa masing-masing</string>
|
<string name="pref_duplicate_pinned_sources_summary">Ulang sumber ditandai pada kelompok bahasa masing-masing</string>
|
||||||
<string name="source_filter_empty_screen">Sumber yang diinstal tidak ditemukan</string>
|
<string name="source_filter_empty_screen">Sumber yang diinstal tidak ditemukan</string>
|
||||||
<string name="source_empty_screen">Tidak ada sumber yang ditemukan</string>
|
<string name="source_empty_screen">Tidak ada sumber yang ditemukan</string>
|
||||||
<string name="action_sort_last_manga_update">Pembaruan manga terakhir</string>
|
<string name="action_sort_last_manga_update">Pembaruan terakhir</string>
|
||||||
<string name="action_sort_unread_count">Jumlah belum dibaca</string>
|
<string name="action_sort_unread_count">Jumlah belum dibaca</string>
|
||||||
<string name="split_tall_images">Membagi gambar panjang</string>
|
<string name="split_tall_images">Membagi gambar panjang</string>
|
||||||
<string name="split_tall_images_summary">Meningkatkan kinerja pembaca</string>
|
<string name="split_tall_images_summary">Meningkatkan kinerja pembaca</string>
|
||||||
|
@ -214,7 +214,7 @@
|
|||||||
<string name="update_check_look_for_updates">Ricerca aggiornamenti…</string>
|
<string name="update_check_look_for_updates">Ricerca aggiornamenti…</string>
|
||||||
<!--UpdateCheck Notifications-->
|
<!--UpdateCheck Notifications-->
|
||||||
<string name="update_check_notification_download_in_progress">Download in corso…</string>
|
<string name="update_check_notification_download_in_progress">Download in corso…</string>
|
||||||
<string name="update_check_notification_download_complete">Tocca per installare</string>
|
<string name="update_check_notification_download_complete">Tocca per installare l\'aggiornamento</string>
|
||||||
<string name="update_check_notification_download_error">Errore di scaricamento</string>
|
<string name="update_check_notification_download_error">Errore di scaricamento</string>
|
||||||
<string name="update_check_notification_update_available">Nuova versione disponibile!</string>
|
<string name="update_check_notification_update_available">Nuova versione disponibile!</string>
|
||||||
<!--Content Description-->
|
<!--Content Description-->
|
||||||
@ -341,7 +341,7 @@
|
|||||||
<string name="action_webview_refresh">Aggiorna</string>
|
<string name="action_webview_refresh">Aggiorna</string>
|
||||||
<string name="pref_category_library">Libreria</string>
|
<string name="pref_category_library">Libreria</string>
|
||||||
<string name="ext_obsolete">Obsoleta</string>
|
<string name="ext_obsolete">Obsoleta</string>
|
||||||
<string name="obsolete_extension_message">Questa estensione non è più disponibile.</string>
|
<string name="obsolete_extension_message">Questa estensione non è più disponibile. Potrebbe non funzionare correttamente e causare problemi con l\'app. Si consiglia di disinstallarla.</string>
|
||||||
<string name="pref_date_format">Formato data</string>
|
<string name="pref_date_format">Formato data</string>
|
||||||
<string name="pref_category_library_update">Aggiornamenti globali</string>
|
<string name="pref_category_library_update">Aggiornamenti globali</string>
|
||||||
<string name="logout_title">Disconnettersi da %1$s\?</string>
|
<string name="logout_title">Disconnettersi da %1$s\?</string>
|
||||||
@ -812,4 +812,10 @@
|
|||||||
<string name="unknown_title">Titolo sconosciuto</string>
|
<string name="unknown_title">Titolo sconosciuto</string>
|
||||||
<string name="error_user_agent_string_invalid">Stringa «user agent» non valida</string>
|
<string name="error_user_agent_string_invalid">Stringa «user agent» non valida</string>
|
||||||
<string name="updates_last_update_info_just_now">Proprio adesso</string>
|
<string name="updates_last_update_info_just_now">Proprio adesso</string>
|
||||||
|
<string name="channel_downloader_cache">Cache di download</string>
|
||||||
|
<string name="download_notifier_cache_renewal">Indicizzazione dei download</string>
|
||||||
|
<string name="action_open_random_manga">Apri una voce casuale</string>
|
||||||
|
<string name="information_no_entries_found">Nessuna voce trovata in questa categoria</string>
|
||||||
|
<string name="fdroid_warning">Le versioni F-Droid non sono ufficialmente supportate.
|
||||||
|
\nToccare per saperne di più.</string>
|
||||||
</resources>
|
</resources>
|
@ -264,7 +264,7 @@
|
|||||||
<string name="update_check_no_new_updates">新しいバージョンがありません</string>
|
<string name="update_check_no_new_updates">新しいバージョンがありません</string>
|
||||||
<string name="update_check_look_for_updates">アップデートを確認中…</string>
|
<string name="update_check_look_for_updates">アップデートを確認中…</string>
|
||||||
<string name="update_check_notification_download_in_progress">ダウンロード中…</string>
|
<string name="update_check_notification_download_in_progress">ダウンロード中…</string>
|
||||||
<string name="update_check_notification_download_complete">タップでインストール</string>
|
<string name="update_check_notification_download_complete">タップでアップデートをインストール</string>
|
||||||
<string name="update_check_notification_download_error">ダウンロード中にエラー発生</string>
|
<string name="update_check_notification_download_error">ダウンロード中にエラー発生</string>
|
||||||
<string name="update_check_notification_update_available">アップデート利用可能!</string>
|
<string name="update_check_notification_update_available">アップデート利用可能!</string>
|
||||||
<string name="information_no_downloads">ダウンロードがありません</string>
|
<string name="information_no_downloads">ダウンロードがありません</string>
|
||||||
@ -302,7 +302,7 @@
|
|||||||
<string name="action_webview_refresh">再ロード</string>
|
<string name="action_webview_refresh">再ロード</string>
|
||||||
<string name="pref_category_library">ライブラリ</string>
|
<string name="pref_category_library">ライブラリ</string>
|
||||||
<string name="ext_obsolete">廃止済み</string>
|
<string name="ext_obsolete">廃止済み</string>
|
||||||
<string name="obsolete_extension_message">この拡張機能は利用不可になりました。</string>
|
<string name="obsolete_extension_message">この拡張機能は利用不可になったため、正常に機能しなかったり、アプリでエラーを起こしたりする恐れがあります。アンインストールすることをお勧めします。</string>
|
||||||
<string name="pref_date_format">日付形式</string>
|
<string name="pref_date_format">日付形式</string>
|
||||||
<string name="pref_category_library_update">グローバルアップデート</string>
|
<string name="pref_category_library_update">グローバルアップデート</string>
|
||||||
<string name="logout_title">%1$sからログアウトしますか?</string>
|
<string name="logout_title">%1$sからログアウトしますか?</string>
|
||||||
@ -431,7 +431,7 @@
|
|||||||
<string name="notification_chapters_single_and_more">第%1$s章とその他%2$d章</string>
|
<string name="notification_chapters_single_and_more">第%1$s章とその他%2$d章</string>
|
||||||
<string name="notification_chapters_multiple">第%1$s章</string>
|
<string name="notification_chapters_multiple">第%1$s章</string>
|
||||||
<plurals name="notification_new_chapters_summary">
|
<plurals name="notification_new_chapters_summary">
|
||||||
<item quantity="other">%d件のタイトル</item>
|
<item quantity="other">%d件の項目</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="recent_manga_time">第%1$s章 - %2$s</string>
|
<string name="recent_manga_time">第%1$s章 - %2$s</string>
|
||||||
<string name="page_list_empty_error">ページが見つかりません</string>
|
<string name="page_list_empty_error">ページが見つかりません</string>
|
||||||
@ -642,7 +642,7 @@
|
|||||||
<string name="database_clean">消去できるものはありませんでした</string>
|
<string name="database_clean">消去できるものはありませんでした</string>
|
||||||
<string name="extension_api_error">拡張機能リストを取得できませんでした</string>
|
<string name="extension_api_error">拡張機能リストを取得できませんでした</string>
|
||||||
<string name="privacy_policy">プライバシーポリシー</string>
|
<string name="privacy_policy">プライバシーポリシー</string>
|
||||||
<string name="pref_library_update_manga_restriction">タイトル更新のスキップ</string>
|
<string name="pref_library_update_manga_restriction">項目更新のスキップ</string>
|
||||||
<string name="pref_update_only_completely_read">未読の章あり</string>
|
<string name="pref_update_only_completely_read">未読の章あり</string>
|
||||||
<string name="library_errors_help">ライブラリ更新エラーの修正については、%1$sをご覧ください</string>
|
<string name="library_errors_help">ライブラリ更新エラーの修正については、%1$sをご覧ください</string>
|
||||||
<string name="save_chapter_as_cbz">CBZアーカイブとして保存</string>
|
<string name="save_chapter_as_cbz">CBZアーカイブとして保存</string>
|
||||||
@ -753,4 +753,10 @@
|
|||||||
<string name="pref_advanced_summary">クラッシュ ログのダンプ、バッテリーの最適化</string>
|
<string name="pref_advanced_summary">クラッシュ ログのダンプ、バッテリーの最適化</string>
|
||||||
<string name="pref_appearance_summary">テーマ、日付と時刻の形式</string>
|
<string name="pref_appearance_summary">テーマ、日付と時刻の形式</string>
|
||||||
<string name="pref_library_summary">カテゴリ、グローバル アップデート</string>
|
<string name="pref_library_summary">カテゴリ、グローバル アップデート</string>
|
||||||
|
<string name="channel_downloader_cache">ダウンロード キャッシュ</string>
|
||||||
|
<string name="action_open_random_manga">おまかせ閲覧</string>
|
||||||
|
<string name="information_no_entries_found">このカテゴリに項目がありません</string>
|
||||||
|
<string name="download_notifier_cache_renewal">ダウンロードのインデックスを作成しています</string>
|
||||||
|
<string name="fdroid_warning">F-Droidビルドは正式にサポートされていません。
|
||||||
|
\n詳細はタップしてご覧ください。</string>
|
||||||
</resources>
|
</resources>
|
@ -225,7 +225,7 @@
|
|||||||
<string name="update_check_no_new_updates">새로운 업데이트 없음</string>
|
<string name="update_check_no_new_updates">새로운 업데이트 없음</string>
|
||||||
<string name="update_check_look_for_updates">업데이트를 찾는중…</string>
|
<string name="update_check_look_for_updates">업데이트를 찾는중…</string>
|
||||||
<string name="update_check_notification_download_in_progress">다운로드 중…</string>
|
<string name="update_check_notification_download_in_progress">다운로드 중…</string>
|
||||||
<string name="update_check_notification_download_complete">탭하여 설치</string>
|
<string name="update_check_notification_download_complete">탭하여 업데이트 설치</string>
|
||||||
<string name="update_check_notification_download_error">다운로드 오류</string>
|
<string name="update_check_notification_download_error">다운로드 오류</string>
|
||||||
<string name="update_check_notification_update_available">업데이트 이용 가능!</string>
|
<string name="update_check_notification_update_available">업데이트 이용 가능!</string>
|
||||||
<string name="information_no_downloads">다운로드 없음</string>
|
<string name="information_no_downloads">다운로드 없음</string>
|
||||||
@ -272,7 +272,7 @@
|
|||||||
<string name="custom_download">다운로드 할 회차 직접 입력</string>
|
<string name="custom_download">다운로드 할 회차 직접 입력</string>
|
||||||
<string name="download_custom">사용자 정의</string>
|
<string name="download_custom">사용자 정의</string>
|
||||||
<string name="reading">읽는 중</string>
|
<string name="reading">읽는 중</string>
|
||||||
<string name="completed">완료</string>
|
<string name="completed">완결</string>
|
||||||
<string name="dropped">포기함</string>
|
<string name="dropped">포기함</string>
|
||||||
<string name="on_hold">일시중지중</string>
|
<string name="on_hold">일시중지중</string>
|
||||||
<string name="plan_to_read">계획중</string>
|
<string name="plan_to_read">계획중</string>
|
||||||
@ -546,7 +546,7 @@
|
|||||||
<string name="information_webview_required">Tachiyomi를 사용하려면 WebView가 필요합니다</string>
|
<string name="information_webview_required">Tachiyomi를 사용하려면 WebView가 필요합니다</string>
|
||||||
<string name="information_webview_outdated">호환성을 위해 WebView 어플리케이션을 업데이트 해 주세요</string>
|
<string name="information_webview_outdated">호환성을 위해 WebView 어플리케이션을 업데이트 해 주세요</string>
|
||||||
<string name="pref_navigate_pan">탭 하여 넓은 이미지 이동</string>
|
<string name="pref_navigate_pan">탭 하여 넓은 이미지 이동</string>
|
||||||
<string name="obsolete_extension_message">이 확장기능은 더이상 이용이 불가능합니다.</string>
|
<string name="obsolete_extension_message">이 확장 프로그램은 더 이상 사용할 수 없습니다. 제대로 작동하지 않을 수 있으며 앱에 문제가 발생할 수 있습니다. 제거하는 것이 좋습니다.</string>
|
||||||
<string name="ext_install_service_notif">확장기능 설치 중…</string>
|
<string name="ext_install_service_notif">확장기능 설치 중…</string>
|
||||||
<string name="ext_installer_legacy">레거시</string>
|
<string name="ext_installer_legacy">레거시</string>
|
||||||
<string name="webtoon_side_padding_10">10%</string>
|
<string name="webtoon_side_padding_10">10%</string>
|
||||||
@ -753,4 +753,10 @@
|
|||||||
<string name="invalid_location">잘못된 위치: %s</string>
|
<string name="invalid_location">잘못된 위치: %s</string>
|
||||||
<string name="error_user_agent_string_invalid">잘못된 사용자 에이전트 문자열</string>
|
<string name="error_user_agent_string_invalid">잘못된 사용자 에이전트 문자열</string>
|
||||||
<string name="updates_last_update_info_just_now">방금</string>
|
<string name="updates_last_update_info_just_now">방금</string>
|
||||||
|
<string name="channel_downloader_cache">캐시 다운로드</string>
|
||||||
|
<string name="download_notifier_cache_renewal">다운로드 인덱싱</string>
|
||||||
|
<string name="action_open_random_manga">무작위 항목 열기</string>
|
||||||
|
<string name="information_no_entries_found">이 카테고리에 항목이 없습니다</string>
|
||||||
|
<string name="fdroid_warning">F-Droid 빌드는 공식적으로 지원되지 않습니다.
|
||||||
|
\n자세히 알아보려면 탭하세요.</string>
|
||||||
</resources>
|
</resources>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user