mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-15 15:02:49 +01:00
Merge branch 'master' into sync-part-1
This commit is contained in:
commit
1af1ce924d
13
.github/renovate.json
vendored
13
.github/renovate.json
vendored
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": [
|
|
||||||
"config:base"
|
|
||||||
],
|
|
||||||
"schedule": ["every sunday"],
|
|
||||||
"packageRules": [
|
|
||||||
{
|
|
||||||
"managers": ["maven"],
|
|
||||||
"packageNames": ["com.google.guava:guava"],
|
|
||||||
"versionScheme": "docker"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
22
.github/renovate.json5
vendored
Normal file
22
.github/renovate.json5
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
],
|
||||||
|
"schedule": ["every sunday"],
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"managers": ["maven"],
|
||||||
|
"packageNames": ["com.google.guava:guava"],
|
||||||
|
"versionScheme": "docker"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Compiler plugins are tightly coupled to Kotlin version
|
||||||
|
"groupName": "Kotlin",
|
||||||
|
"matchPackagePrefixes": [
|
||||||
|
"androidx.compose.compiler",
|
||||||
|
"org.jetbrains.kotlin",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -23,7 +23,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "eu.kanade.tachiyomi"
|
applicationId = "eu.kanade.tachiyomi"
|
||||||
|
|
||||||
versionCode = 103
|
versionCode = 104
|
||||||
versionName = "0.14.6"
|
versionName = "0.14.6"
|
||||||
|
|
||||||
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
|
||||||
@ -239,6 +239,7 @@ dependencies {
|
|||||||
implementation(libs.bundles.voyager)
|
implementation(libs.bundles.voyager)
|
||||||
implementation(libs.compose.materialmotion)
|
implementation(libs.compose.materialmotion)
|
||||||
implementation(libs.compose.simpleicons)
|
implementation(libs.compose.simpleicons)
|
||||||
|
implementation(libs.swipe)
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation(libs.logcat)
|
implementation(libs.logcat)
|
||||||
|
@ -16,6 +16,7 @@ import eu.kanade.domain.source.interactor.SetMigrateSorting
|
|||||||
import eu.kanade.domain.source.interactor.ToggleLanguage
|
import eu.kanade.domain.source.interactor.ToggleLanguage
|
||||||
import eu.kanade.domain.source.interactor.ToggleSource
|
import eu.kanade.domain.source.interactor.ToggleSource
|
||||||
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
import eu.kanade.domain.source.interactor.ToggleSourcePin
|
||||||
|
import eu.kanade.domain.track.interactor.TrackChapter
|
||||||
import tachiyomi.data.category.CategoryRepositoryImpl
|
import tachiyomi.data.category.CategoryRepositoryImpl
|
||||||
import tachiyomi.data.chapter.ChapterRepositoryImpl
|
import tachiyomi.data.chapter.ChapterRepositoryImpl
|
||||||
import tachiyomi.data.history.HistoryRepositoryImpl
|
import tachiyomi.data.history.HistoryRepositoryImpl
|
||||||
@ -109,6 +110,7 @@ class DomainModule : InjektModule {
|
|||||||
addFactory { GetApplicationRelease(get(), get()) }
|
addFactory { GetApplicationRelease(get(), get()) }
|
||||||
|
|
||||||
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
||||||
|
addFactory { TrackChapter(get(), get(), get(), get()) }
|
||||||
addFactory { DeleteTrack(get()) }
|
addFactory { DeleteTrack(get()) }
|
||||||
addFactory { GetTracksPerManga(get()) }
|
addFactory { GetTracksPerManga(get()) }
|
||||||
addFactory { GetTracks(get()) }
|
addFactory { GetTracks(get()) }
|
||||||
|
@ -7,9 +7,9 @@ import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
|||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||||
import tachiyomi.core.metadata.comicinfo.ComicInfo
|
import tachiyomi.core.metadata.comicinfo.ComicInfo
|
||||||
import tachiyomi.core.metadata.comicinfo.ComicInfoPublishingStatus
|
import tachiyomi.core.metadata.comicinfo.ComicInfoPublishingStatus
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -20,19 +20,19 @@ val Manga.readingModeType: Long
|
|||||||
val Manga.orientationType: Long
|
val Manga.orientationType: Long
|
||||||
get() = viewerFlags and OrientationType.MASK.toLong()
|
get() = viewerFlags and OrientationType.MASK.toLong()
|
||||||
|
|
||||||
val Manga.downloadedFilter: TriStateFilter
|
val Manga.downloadedFilter: TriState
|
||||||
get() {
|
get() {
|
||||||
if (forceDownloaded()) return TriStateFilter.ENABLED_IS
|
if (forceDownloaded()) return TriState.ENABLED_IS
|
||||||
return when (downloadedFilterRaw) {
|
return when (downloadedFilterRaw) {
|
||||||
Manga.CHAPTER_SHOW_DOWNLOADED -> TriStateFilter.ENABLED_IS
|
Manga.CHAPTER_SHOW_DOWNLOADED -> TriState.ENABLED_IS
|
||||||
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriStateFilter.ENABLED_NOT
|
Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> TriState.ENABLED_NOT
|
||||||
else -> TriStateFilter.DISABLED
|
else -> TriState.DISABLED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun Manga.chaptersFiltered(): Boolean {
|
fun Manga.chaptersFiltered(): Boolean {
|
||||||
return unreadFilter != TriStateFilter.DISABLED ||
|
return unreadFilter != TriState.DISABLED ||
|
||||||
downloadedFilter != TriStateFilter.DISABLED ||
|
downloadedFilter != TriState.DISABLED ||
|
||||||
bookmarkedFilter != TriStateFilter.DISABLED
|
bookmarkedFilter != TriState.DISABLED
|
||||||
}
|
}
|
||||||
fun Manga.forceDownloaded(): Boolean {
|
fun Manga.forceDownloaded(): Boolean {
|
||||||
return favorite && Injekt.get<BasePreferences>().downloadedOnly().get()
|
return favorite && Injekt.get<BasePreferences>().downloadedOnly().get()
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.kanade.domain.track.model.toDbTrack
|
||||||
|
import eu.kanade.domain.track.service.DelayedTrackingUpdateJob
|
||||||
|
import eu.kanade.domain.track.store.DelayedTrackingStore
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import logcat.LogPriority
|
||||||
|
import tachiyomi.core.util.lang.launchNonCancellable
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
|
import tachiyomi.domain.track.interactor.InsertTrack
|
||||||
|
|
||||||
|
class TrackChapter(
|
||||||
|
private val getTracks: GetTracks,
|
||||||
|
private val trackManager: TrackManager,
|
||||||
|
private val insertTrack: InsertTrack,
|
||||||
|
private val delayedTrackingStore: DelayedTrackingStore,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun await(context: Context, mangaId: Long, chapterNumber: Double) = coroutineScope {
|
||||||
|
launchNonCancellable {
|
||||||
|
val tracks = getTracks.await(mangaId)
|
||||||
|
|
||||||
|
if (tracks.isEmpty()) return@launchNonCancellable
|
||||||
|
|
||||||
|
tracks.mapNotNull { track ->
|
||||||
|
val service = trackManager.getService(track.syncId)
|
||||||
|
if (service != null && service.isLogged && chapterNumber > track.lastChapterRead) {
|
||||||
|
val updatedTrack = track.copy(lastChapterRead = chapterNumber)
|
||||||
|
|
||||||
|
async {
|
||||||
|
runCatching {
|
||||||
|
try {
|
||||||
|
service.update(updatedTrack.toDbTrack(), true)
|
||||||
|
insertTrack.await(updatedTrack)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
delayedTrackingStore.addItem(updatedTrack)
|
||||||
|
DelayedTrackingUpdateJob.setupTask(context)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.awaitAll()
|
||||||
|
.mapNotNull { it.exceptionOrNull() }
|
||||||
|
.forEach { logcat(LogPriority.INFO, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ 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.LazyColumn
|
||||||
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
|
||||||
@ -19,7 +20,6 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchState
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.presentation.browse
|
package eu.kanade.presentation.browse
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
|
||||||
@ -14,7 +15,6 @@ import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchState
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.presentation.browse.components
|
package eu.kanade.presentation.browse.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@ -12,7 +13,6 @@ import eu.kanade.presentation.library.components.MangaListItem
|
|||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.MangaCover
|
import tachiyomi.domain.manga.model.MangaCover
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.util.plus
|
import tachiyomi.presentation.core.util.plus
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -3,6 +3,7 @@ package eu.kanade.presentation.category
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
@ -16,7 +17,6 @@ import eu.kanade.presentation.components.AppBar
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.category.CategoryScreenState
|
import eu.kanade.tachiyomi.ui.category.CategoryScreenState
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
|
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
|
||||||
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||||||
import androidx.compose.material.TextFieldDefaults
|
import androidx.compose.material.TextFieldDefaults
|
||||||
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.ArrowForward
|
||||||
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.material.icons.outlined.Search
|
||||||
@ -38,12 +39,14 @@ import androidx.compose.ui.graphics.Color
|
|||||||
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.LocalFocusManager
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
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.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.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -62,7 +65,7 @@ fun AppBar(
|
|||||||
subtitle: String? = null,
|
subtitle: String? = null,
|
||||||
// Up button
|
// Up button
|
||||||
navigateUp: (() -> Unit)? = null,
|
navigateUp: (() -> Unit)? = null,
|
||||||
navigationIcon: ImageVector = Icons.Outlined.ArrowBack,
|
navigationIcon: ImageVector? = null,
|
||||||
// Menu
|
// Menu
|
||||||
actions: @Composable RowScope.() -> Unit = {},
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
// Action mode
|
// Action mode
|
||||||
@ -107,7 +110,7 @@ fun AppBar(
|
|||||||
titleContent: @Composable () -> Unit,
|
titleContent: @Composable () -> Unit,
|
||||||
// Up button
|
// Up button
|
||||||
navigateUp: (() -> Unit)? = null,
|
navigateUp: (() -> Unit)? = null,
|
||||||
navigationIcon: ImageVector = Icons.Outlined.ArrowBack,
|
navigationIcon: ImageVector? = null,
|
||||||
// Menu
|
// Menu
|
||||||
actions: @Composable RowScope.() -> Unit = {},
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
// Action mode
|
// Action mode
|
||||||
@ -131,10 +134,7 @@ fun AppBar(
|
|||||||
} else {
|
} else {
|
||||||
navigateUp?.let {
|
navigateUp?.let {
|
||||||
IconButton(onClick = it) {
|
IconButton(onClick = it) {
|
||||||
Icon(
|
UpIcon(navigationIcon)
|
||||||
imageVector = navigationIcon,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,6 +360,16 @@ fun SearchToolbar(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun UpIcon(navigationIcon: ImageVector? = null) {
|
||||||
|
val icon = navigationIcon
|
||||||
|
?: if (LocalLayoutDirection.current == LayoutDirection.Ltr) Icons.Outlined.ArrowBack else Icons.Outlined.ArrowForward
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
sealed interface AppBar {
|
sealed interface AppBar {
|
||||||
sealed interface AppBarAction
|
sealed interface AppBarAction
|
||||||
|
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
package eu.kanade.presentation.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.ContentAlpha
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.rounded.CheckBox
|
|
||||||
import androidx.compose.material.icons.rounded.CheckBoxOutlineBlank
|
|
||||||
import androidx.compose.material.icons.rounded.DisabledByDefault
|
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
|
||||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
|
||||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
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.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import tachiyomi.presentation.core.components.SettingsItemsPaddings
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun TriStateItem(
|
|
||||||
label: String,
|
|
||||||
state: TriStateFilter,
|
|
||||||
enabled: Boolean = true,
|
|
||||||
onClick: ((TriStateFilter) -> Unit)?,
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable(
|
|
||||||
enabled = enabled && onClick != null,
|
|
||||||
onClick = {
|
|
||||||
when (state) {
|
|
||||||
TriStateFilter.DISABLED -> onClick?.invoke(TriStateFilter.ENABLED_IS)
|
|
||||||
TriStateFilter.ENABLED_IS -> onClick?.invoke(TriStateFilter.ENABLED_NOT)
|
|
||||||
TriStateFilter.ENABLED_NOT -> onClick?.invoke(TriStateFilter.DISABLED)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = SettingsItemsPaddings.Horizontal, vertical = SettingsItemsPaddings.Vertical),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(24.dp),
|
|
||||||
) {
|
|
||||||
val stateAlpha = if (enabled && onClick != null) 1f else ContentAlpha.disabled
|
|
||||||
|
|
||||||
Icon(
|
|
||||||
imageVector = when (state) {
|
|
||||||
TriStateFilter.DISABLED -> Icons.Rounded.CheckBoxOutlineBlank
|
|
||||||
TriStateFilter.ENABLED_IS -> Icons.Rounded.CheckBox
|
|
||||||
TriStateFilter.ENABLED_NOT -> Icons.Rounded.DisabledByDefault
|
|
||||||
},
|
|
||||||
contentDescription = null,
|
|
||||||
tint = if (!enabled || state == TriStateFilter.DISABLED) {
|
|
||||||
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = stateAlpha)
|
|
||||||
} else {
|
|
||||||
when (onClick) {
|
|
||||||
null -> MaterialTheme.colorScheme.onSurface.copy(alpha = ContentAlpha.disabled)
|
|
||||||
else -> MaterialTheme.colorScheme.primary
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = label,
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = stateAlpha),
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun SelectItem(
|
|
||||||
label: String,
|
|
||||||
options: Array<out Any?>,
|
|
||||||
selectedIndex: Int,
|
|
||||||
onSelect: (Int) -> Unit,
|
|
||||||
) {
|
|
||||||
var expanded by remember { mutableStateOf(false) }
|
|
||||||
|
|
||||||
ExposedDropdownMenuBox(
|
|
||||||
expanded = expanded,
|
|
||||||
onExpandedChange = { expanded = !expanded },
|
|
||||||
) {
|
|
||||||
OutlinedTextField(
|
|
||||||
modifier = Modifier
|
|
||||||
.menuAnchor()
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = SettingsItemsPaddings.Horizontal, vertical = SettingsItemsPaddings.Vertical),
|
|
||||||
label = { Text(text = label) },
|
|
||||||
value = options[selectedIndex].toString(),
|
|
||||||
onValueChange = {},
|
|
||||||
readOnly = true,
|
|
||||||
singleLine = true,
|
|
||||||
trailingIcon = {
|
|
||||||
ExposedDropdownMenuDefaults.TrailingIcon(
|
|
||||||
expanded = expanded,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
colors = ExposedDropdownMenuDefaults.textFieldColors(),
|
|
||||||
)
|
|
||||||
|
|
||||||
ExposedDropdownMenu(
|
|
||||||
modifier = Modifier.exposedDropdownSize(matchTextFieldWidth = true),
|
|
||||||
expanded = expanded,
|
|
||||||
onDismissRequest = { expanded = false },
|
|
||||||
) {
|
|
||||||
options.forEachIndexed { index, text ->
|
|
||||||
DropdownMenuItem(
|
|
||||||
text = { Text(text.toString()) },
|
|
||||||
onClick = {
|
|
||||||
onSelect(index)
|
|
||||||
expanded = false
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.foundation.pager.PagerState
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
@ -42,13 +43,13 @@ fun TabbedDialog(
|
|||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
tabTitles: List<String>,
|
tabTitles: List<String>,
|
||||||
tabOverflowMenuContent: (@Composable ColumnScope.(() -> Unit) -> Unit)? = null,
|
tabOverflowMenuContent: (@Composable ColumnScope.(() -> Unit) -> Unit)? = null,
|
||||||
|
pagerState: PagerState = rememberPagerState { tabTitles.size },
|
||||||
content: @Composable (Int) -> Unit,
|
content: @Composable (Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
AdaptiveSheet(
|
AdaptiveSheet(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val pagerState = rememberPagerState { tabTitles.size }
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
Row {
|
Row {
|
||||||
|
@ -14,21 +14,21 @@ import androidx.compose.ui.platform.LocalConfiguration
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import eu.kanade.presentation.components.TabbedDialog
|
import eu.kanade.presentation.components.TabbedDialog
|
||||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||||
import eu.kanade.presentation.components.TriStateItem
|
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.ui.library.LibrarySettingsScreenModel
|
import eu.kanade.tachiyomi.ui.library.LibrarySettingsScreenModel
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.domain.category.model.Category
|
import tachiyomi.domain.category.model.Category
|
||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
import tachiyomi.domain.library.model.LibrarySort
|
import tachiyomi.domain.library.model.LibrarySort
|
||||||
import tachiyomi.domain.library.model.sort
|
import tachiyomi.domain.library.model.sort
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import tachiyomi.presentation.core.components.CheckboxItem
|
import tachiyomi.presentation.core.components.CheckboxItem
|
||||||
import tachiyomi.presentation.core.components.HeadingItem
|
import tachiyomi.presentation.core.components.HeadingItem
|
||||||
import tachiyomi.presentation.core.components.RadioItem
|
import tachiyomi.presentation.core.components.RadioItem
|
||||||
import tachiyomi.presentation.core.components.SliderItem
|
import tachiyomi.presentation.core.components.SliderItem
|
||||||
import tachiyomi.presentation.core.components.SortItem
|
import tachiyomi.presentation.core.components.SortItem
|
||||||
|
import tachiyomi.presentation.core.components.TriStateItem
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LibrarySettingsDialog(
|
fun LibrarySettingsDialog(
|
||||||
@ -74,7 +74,7 @@ private fun ColumnScope.FilterPage(
|
|||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(R.string.label_downloaded),
|
label = stringResource(R.string.label_downloaded),
|
||||||
state = if (downloadedOnly) {
|
state = if (downloadedOnly) {
|
||||||
TriStateFilter.ENABLED_IS
|
TriState.ENABLED_IS
|
||||||
} else {
|
} else {
|
||||||
filterDownloaded
|
filterDownloaded
|
||||||
},
|
},
|
||||||
|
@ -27,20 +27,20 @@ import eu.kanade.domain.manga.model.downloadedFilter
|
|||||||
import eu.kanade.domain.manga.model.forceDownloaded
|
import eu.kanade.domain.manga.model.forceDownloaded
|
||||||
import eu.kanade.presentation.components.TabbedDialog
|
import eu.kanade.presentation.components.TabbedDialog
|
||||||
import eu.kanade.presentation.components.TabbedDialogPaddings
|
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||||
import eu.kanade.presentation.components.TriStateItem
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import tachiyomi.presentation.core.components.RadioItem
|
import tachiyomi.presentation.core.components.RadioItem
|
||||||
import tachiyomi.presentation.core.components.SortItem
|
import tachiyomi.presentation.core.components.SortItem
|
||||||
|
import tachiyomi.presentation.core.components.TriStateItem
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChapterSettingsDialog(
|
fun ChapterSettingsDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
manga: Manga? = null,
|
manga: Manga? = null,
|
||||||
onDownloadFilterChanged: (TriStateFilter) -> Unit,
|
onDownloadFilterChanged: (TriState) -> Unit,
|
||||||
onUnreadFilterChanged: (TriStateFilter) -> Unit,
|
onUnreadFilterChanged: (TriState) -> Unit,
|
||||||
onBookmarkedFilterChanged: (TriStateFilter) -> Unit,
|
onBookmarkedFilterChanged: (TriState) -> Unit,
|
||||||
onSortModeChanged: (Long) -> Unit,
|
onSortModeChanged: (Long) -> Unit,
|
||||||
onDisplayModeChanged: (Long) -> Unit,
|
onDisplayModeChanged: (Long) -> Unit,
|
||||||
onSetAsDefault: (applyToExistingManga: Boolean) -> Unit,
|
onSetAsDefault: (applyToExistingManga: Boolean) -> Unit,
|
||||||
@ -78,11 +78,11 @@ fun ChapterSettingsDialog(
|
|||||||
when (page) {
|
when (page) {
|
||||||
0 -> {
|
0 -> {
|
||||||
FilterPage(
|
FilterPage(
|
||||||
downloadFilter = manga?.downloadedFilter ?: TriStateFilter.DISABLED,
|
downloadFilter = manga?.downloadedFilter ?: TriState.DISABLED,
|
||||||
onDownloadFilterChanged = onDownloadFilterChanged.takeUnless { manga?.forceDownloaded() == true },
|
onDownloadFilterChanged = onDownloadFilterChanged.takeUnless { manga?.forceDownloaded() == true },
|
||||||
unreadFilter = manga?.unreadFilter ?: TriStateFilter.DISABLED,
|
unreadFilter = manga?.unreadFilter ?: TriState.DISABLED,
|
||||||
onUnreadFilterChanged = onUnreadFilterChanged,
|
onUnreadFilterChanged = onUnreadFilterChanged,
|
||||||
bookmarkedFilter = manga?.bookmarkedFilter ?: TriStateFilter.DISABLED,
|
bookmarkedFilter = manga?.bookmarkedFilter ?: TriState.DISABLED,
|
||||||
onBookmarkedFilterChanged = onBookmarkedFilterChanged,
|
onBookmarkedFilterChanged = onBookmarkedFilterChanged,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -106,12 +106,12 @@ fun ChapterSettingsDialog(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ColumnScope.FilterPage(
|
private fun ColumnScope.FilterPage(
|
||||||
downloadFilter: TriStateFilter,
|
downloadFilter: TriState,
|
||||||
onDownloadFilterChanged: ((TriStateFilter) -> Unit)?,
|
onDownloadFilterChanged: ((TriState) -> Unit)?,
|
||||||
unreadFilter: TriStateFilter,
|
unreadFilter: TriState,
|
||||||
onUnreadFilterChanged: (TriStateFilter) -> Unit,
|
onUnreadFilterChanged: (TriState) -> Unit,
|
||||||
bookmarkedFilter: TriStateFilter,
|
bookmarkedFilter: TriState,
|
||||||
onBookmarkedFilterChanged: (TriStateFilter) -> Unit,
|
onBookmarkedFilterChanged: (TriState) -> Unit,
|
||||||
) {
|
) {
|
||||||
TriStateItem(
|
TriStateItem(
|
||||||
label = stringResource(R.string.label_downloaded),
|
label = stringResource(R.string.label_downloaded),
|
||||||
|
@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
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
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListScope
|
import androidx.compose.foundation.lazy.LazyListScope
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
@ -69,7 +70,6 @@ import tachiyomi.domain.chapter.service.missingChaptersCount
|
|||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.model.StubSource
|
import tachiyomi.domain.source.model.StubSource
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.TwoPanelBox
|
import tachiyomi.presentation.core.components.TwoPanelBox
|
||||||
import tachiyomi.presentation.core.components.VerticalFastScroller
|
import tachiyomi.presentation.core.components.VerticalFastScroller
|
||||||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||||
@ -87,8 +87,8 @@ fun MangaScreen(
|
|||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
isTabletUi: Boolean,
|
isTabletUi: Boolean,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
@ -141,8 +141,8 @@ fun MangaScreen(
|
|||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onBackClicked = onBackClicked,
|
onBackClicked = onBackClicked,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
onDownloadChapter = onDownloadChapter,
|
onDownloadChapter = onDownloadChapter,
|
||||||
@ -175,8 +175,8 @@ fun MangaScreen(
|
|||||||
state = state,
|
state = state,
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
onBackClicked = onBackClicked,
|
onBackClicked = onBackClicked,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
@ -214,8 +214,8 @@ private fun MangaScreenSmallImpl(
|
|||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
@ -258,7 +258,7 @@ private fun MangaScreenSmallImpl(
|
|||||||
) {
|
) {
|
||||||
val chapterListState = rememberLazyListState()
|
val chapterListState = rememberLazyListState()
|
||||||
|
|
||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters }
|
||||||
|
|
||||||
val internalOnBackPressed = {
|
val internalOnBackPressed = {
|
||||||
if (chapters.fastAny { it.selected }) {
|
if (chapters.fastAny { it.selected }) {
|
||||||
@ -320,7 +320,7 @@ private fun MangaScreenSmallImpl(
|
|||||||
) {
|
) {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = {
|
text = {
|
||||||
val id = if (chapters.fastAny { it.chapter.read }) {
|
val id = if (state.chapters.fastAny { it.chapter.read }) {
|
||||||
R.string.action_resume
|
R.string.action_resume
|
||||||
} else {
|
} else {
|
||||||
R.string.action_start
|
R.string.action_start
|
||||||
@ -421,8 +421,8 @@ private fun MangaScreenSmallImpl(
|
|||||||
chapters = chapters,
|
chapters = chapters,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
onDownloadChapter = onDownloadChapter,
|
onDownloadChapter = onDownloadChapter,
|
||||||
onChapterSelected = onChapterSelected,
|
onChapterSelected = onChapterSelected,
|
||||||
@ -440,8 +440,8 @@ fun MangaScreenLargeImpl(
|
|||||||
snackbarHostState: SnackbarHostState,
|
snackbarHostState: SnackbarHostState,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onBackClicked: () -> Unit,
|
onBackClicked: () -> Unit,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
@ -485,7 +485,7 @@ fun MangaScreenLargeImpl(
|
|||||||
val layoutDirection = LocalLayoutDirection.current
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
|
||||||
val chapters = remember(state) { state.processedChapters.toList() }
|
val chapters = remember(state) { state.processedChapters }
|
||||||
|
|
||||||
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
|
||||||
var topBarHeight by remember { mutableIntStateOf(0) }
|
var topBarHeight by remember { mutableIntStateOf(0) }
|
||||||
@ -555,7 +555,7 @@ fun MangaScreenLargeImpl(
|
|||||||
) {
|
) {
|
||||||
ExtendedFloatingActionButton(
|
ExtendedFloatingActionButton(
|
||||||
text = {
|
text = {
|
||||||
val id = if (chapters.fastAny { it.chapter.read }) {
|
val id = if (state.chapters.fastAny { it.chapter.read }) {
|
||||||
R.string.action_resume
|
R.string.action_resume
|
||||||
} else {
|
} else {
|
||||||
R.string.action_start
|
R.string.action_start
|
||||||
@ -641,8 +641,8 @@ fun MangaScreenLargeImpl(
|
|||||||
chapters = chapters,
|
chapters = chapters,
|
||||||
dateRelativeTime = dateRelativeTime,
|
dateRelativeTime = dateRelativeTime,
|
||||||
dateFormat = dateFormat,
|
dateFormat = dateFormat,
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onChapterClicked = onChapterClicked,
|
onChapterClicked = onChapterClicked,
|
||||||
onDownloadChapter = onDownloadChapter,
|
onDownloadChapter = onDownloadChapter,
|
||||||
onChapterSelected = onChapterSelected,
|
onChapterSelected = onChapterSelected,
|
||||||
@ -703,8 +703,8 @@ private fun LazyListScope.sharedChapterItems(
|
|||||||
chapters: List<ChapterItem>,
|
chapters: List<ChapterItem>,
|
||||||
dateRelativeTime: Int,
|
dateRelativeTime: Int,
|
||||||
dateFormat: DateFormat,
|
dateFormat: DateFormat,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onChapterClicked: (Chapter) -> Unit,
|
onChapterClicked: (Chapter) -> Unit,
|
||||||
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
onDownloadChapter: ((List<ChapterItem>, ChapterDownloadAction) -> Unit)?,
|
||||||
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
|
onChapterSelected: (ChapterItem, Boolean, Boolean, Boolean) -> Unit,
|
||||||
@ -751,8 +751,8 @@ private fun LazyListScope.sharedChapterItems(
|
|||||||
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
|
downloadIndicatorEnabled = chapters.fastAll { !it.selected },
|
||||||
downloadStateProvider = { chapterItem.downloadState },
|
downloadStateProvider = { chapterItem.downloadState },
|
||||||
downloadProgressProvider = { chapterItem.downloadProgress },
|
downloadProgressProvider = { chapterItem.downloadProgress },
|
||||||
chapterSwipeEndAction = chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = chapterSwipeStartAction,
|
chapterSwipeStartAction = chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = chapterSwipeEndAction,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
onChapterSelected(chapterItem, !chapterItem.selected, true, true)
|
onChapterSelected(chapterItem, !chapterItem.selected, true, true)
|
||||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
@ -1,20 +1,12 @@
|
|||||||
package eu.kanade.presentation.manga.components
|
package eu.kanade.presentation.manga.components
|
||||||
|
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.sizeIn
|
import androidx.compose.foundation.layout.sizeIn
|
||||||
import androidx.compose.material.DismissDirection
|
|
||||||
import androidx.compose.material.DismissValue
|
|
||||||
import androidx.compose.material.SwipeToDismiss
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Bookmark
|
import androidx.compose.material.icons.filled.Bookmark
|
||||||
import androidx.compose.material.icons.filled.Circle
|
import androidx.compose.material.icons.filled.Circle
|
||||||
@ -25,7 +17,6 @@ import androidx.compose.material.icons.outlined.Done
|
|||||||
import androidx.compose.material.icons.outlined.Download
|
import androidx.compose.material.icons.outlined.Download
|
||||||
import androidx.compose.material.icons.outlined.FileDownloadOff
|
import androidx.compose.material.icons.outlined.FileDownloadOff
|
||||||
import androidx.compose.material.icons.outlined.RemoveDone
|
import androidx.compose.material.icons.outlined.RemoveDone
|
||||||
import androidx.compose.material.rememberDismissState
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -37,14 +28,18 @@ import androidx.compose.runtime.CompositionLocalProvider
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
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.runtime.snapshotFlow
|
||||||
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.draw.clipToBounds
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
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.LocalViewConfiguration
|
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||||
import androidx.compose.ui.platform.ViewConfiguration
|
import androidx.compose.ui.platform.ViewConfiguration
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -53,10 +48,13 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
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 me.saket.swipe.SwipeableActionsBox
|
||||||
|
import me.saket.swipe.rememberSwipeableActionsState
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
import tachiyomi.presentation.core.components.material.ReadItemAlpha
|
||||||
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
|
||||||
import tachiyomi.presentation.core.util.selectedBackground
|
import tachiyomi.presentation.core.util.selectedBackground
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MangaChapterListItem(
|
fun MangaChapterListItem(
|
||||||
@ -71,13 +69,19 @@ fun MangaChapterListItem(
|
|||||||
downloadIndicatorEnabled: Boolean,
|
downloadIndicatorEnabled: Boolean,
|
||||||
downloadStateProvider: () -> Download.State,
|
downloadStateProvider: () -> Download.State,
|
||||||
downloadProgressProvider: () -> Int,
|
downloadProgressProvider: () -> Int,
|
||||||
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
|
chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
|
onDownloadClick: ((ChapterDownloadAction) -> Unit)?,
|
||||||
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
|
onChapterSwipe: (LibraryPreferences.ChapterSwipeAction) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val haptic = LocalHapticFeedback.current
|
||||||
|
val density = LocalDensity.current
|
||||||
|
|
||||||
|
val textAlpha = if (read) ReadItemAlpha else 1f
|
||||||
|
val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha
|
||||||
|
|
||||||
// Increase touch slop of swipe action to reduce accidental trigger
|
// Increase touch slop of swipe action to reduce accidental trigger
|
||||||
val configuration = LocalViewConfiguration.current
|
val configuration = LocalViewConfiguration.current
|
||||||
CompositionLocalProvider(
|
CompositionLocalProvider(
|
||||||
@ -85,247 +89,188 @@ fun MangaChapterListItem(
|
|||||||
override val touchSlop: Float = configuration.touchSlop * 3f
|
override val touchSlop: Float = configuration.touchSlop * 3f
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
val textAlpha = if (read) ReadItemAlpha else 1f
|
val start = getSwipeAction(
|
||||||
val textSubtitleAlpha = if (read) ReadItemAlpha else SecondaryItemAlpha
|
action = chapterSwipeStartAction,
|
||||||
|
read = read,
|
||||||
val chapterSwipeStartEnabled = chapterSwipeStartAction != LibraryPreferences.ChapterSwipeAction.Disabled
|
bookmark = bookmark,
|
||||||
val chapterSwipeEndEnabled = chapterSwipeEndAction != LibraryPreferences.ChapterSwipeAction.Disabled
|
downloadState = downloadStateProvider(),
|
||||||
|
background = MaterialTheme.colorScheme.primaryContainer,
|
||||||
val dismissState = rememberDismissState()
|
onSwipe = { onChapterSwipe(chapterSwipeStartAction) },
|
||||||
val dismissDirections = remember { mutableSetOf<DismissDirection>() }
|
|
||||||
var lastDismissDirection: DismissDirection? by remember { mutableStateOf(null) }
|
|
||||||
if (lastDismissDirection == null) {
|
|
||||||
if (chapterSwipeStartEnabled) {
|
|
||||||
dismissDirections.add(DismissDirection.EndToStart)
|
|
||||||
}
|
|
||||||
if (chapterSwipeEndEnabled) {
|
|
||||||
dismissDirections.add(DismissDirection.StartToEnd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val animateDismissContentAlpha by animateFloatAsState(
|
|
||||||
label = "animateDismissContentAlpha",
|
|
||||||
targetValue = if (lastDismissDirection != null) 1f else 0f,
|
|
||||||
animationSpec = tween(durationMillis = if (lastDismissDirection != null) 500 else 0),
|
|
||||||
finishedListener = {
|
|
||||||
lastDismissDirection = null
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
val dismissContentAlpha = if (lastDismissDirection != null) animateDismissContentAlpha else 1f
|
val end = getSwipeAction(
|
||||||
val backgroundColor = if (chapterSwipeEndEnabled && (dismissState.dismissDirection == DismissDirection.StartToEnd || lastDismissDirection == DismissDirection.StartToEnd)) {
|
action = chapterSwipeEndAction,
|
||||||
MaterialTheme.colorScheme.primary
|
read = read,
|
||||||
} else if (chapterSwipeStartEnabled && (dismissState.dismissDirection == DismissDirection.EndToStart || lastDismissDirection == DismissDirection.EndToStart)) {
|
bookmark = bookmark,
|
||||||
MaterialTheme.colorScheme.primary
|
downloadState = downloadStateProvider(),
|
||||||
} else {
|
background = MaterialTheme.colorScheme.primaryContainer,
|
||||||
Color.Unspecified
|
onSwipe = { onChapterSwipe(chapterSwipeEndAction) },
|
||||||
|
)
|
||||||
|
|
||||||
|
val swipeableActionsState = rememberSwipeableActionsState()
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
// Haptic effect when swipe over threshold
|
||||||
|
val swipeActionThresholdPx = with(density) { swipeActionThreshold.toPx() }
|
||||||
|
snapshotFlow { swipeableActionsState.offset.value.absoluteValue > swipeActionThresholdPx }
|
||||||
|
.collect { if (it) haptic.performHapticFeedback(HapticFeedbackType.LongPress) }
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(dismissState.currentValue) {
|
SwipeableActionsBox(
|
||||||
when (dismissState.currentValue) {
|
modifier = Modifier.clipToBounds(),
|
||||||
DismissValue.DismissedToEnd -> {
|
state = swipeableActionsState,
|
||||||
lastDismissDirection = DismissDirection.StartToEnd
|
startActions = listOfNotNull(start),
|
||||||
val dismissDirectionsCopy = dismissDirections.toSet()
|
endActions = listOfNotNull(end),
|
||||||
dismissDirections.clear()
|
swipeThreshold = swipeActionThreshold,
|
||||||
onChapterSwipe(chapterSwipeEndAction)
|
backgroundUntilSwipeThreshold = MaterialTheme.colorScheme.surfaceContainerLowest,
|
||||||
dismissState.snapTo(DismissValue.Default)
|
) {
|
||||||
dismissDirections.addAll(dismissDirectionsCopy)
|
Row(
|
||||||
}
|
modifier = modifier
|
||||||
DismissValue.DismissedToStart -> {
|
.selectedBackground(selected)
|
||||||
lastDismissDirection = DismissDirection.EndToStart
|
.combinedClickable(
|
||||||
val dismissDirectionsCopy = dismissDirections.toSet()
|
onClick = onClick,
|
||||||
dismissDirections.clear()
|
onLongClick = onLongClick,
|
||||||
onChapterSwipe(chapterSwipeStartAction)
|
)
|
||||||
dismissState.snapTo(DismissValue.Default)
|
.padding(start = 16.dp, top = 12.dp, end = 8.dp, bottom = 12.dp),
|
||||||
dismissDirections.addAll(dismissDirectionsCopy)
|
) {
|
||||||
}
|
Column(
|
||||||
DismissValue.Default -> { }
|
modifier = Modifier.weight(1f),
|
||||||
}
|
verticalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
}
|
|
||||||
|
|
||||||
SwipeToDismiss(
|
|
||||||
state = dismissState,
|
|
||||||
directions = dismissDirections,
|
|
||||||
background = {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(backgroundColor),
|
|
||||||
) {
|
) {
|
||||||
if (dismissState.dismissDirection in dismissDirections) {
|
Row(
|
||||||
val downloadState = downloadStateProvider()
|
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
||||||
SwipeBackgroundIcon(
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = 16.dp)
|
|
||||||
.align(Alignment.CenterStart)
|
|
||||||
.alpha(
|
|
||||||
if (dismissState.dismissDirection == DismissDirection.StartToEnd) 1f else 0f,
|
|
||||||
),
|
|
||||||
tint = contentColorFor(backgroundColor),
|
|
||||||
swipeAction = chapterSwipeEndAction,
|
|
||||||
read = read,
|
|
||||||
bookmark = bookmark,
|
|
||||||
downloadState = downloadState,
|
|
||||||
)
|
|
||||||
SwipeBackgroundIcon(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 16.dp)
|
|
||||||
.align(Alignment.CenterEnd)
|
|
||||||
.alpha(
|
|
||||||
if (dismissState.dismissDirection == DismissDirection.EndToStart) 1f else 0f,
|
|
||||||
),
|
|
||||||
tint = contentColorFor(backgroundColor),
|
|
||||||
swipeAction = chapterSwipeStartAction,
|
|
||||||
read = read,
|
|
||||||
bookmark = bookmark,
|
|
||||||
downloadState = downloadState,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissContent = {
|
|
||||||
Row(
|
|
||||||
modifier = modifier
|
|
||||||
.background(
|
|
||||||
MaterialTheme.colorScheme.background.copy(dismissContentAlpha),
|
|
||||||
)
|
|
||||||
.selectedBackground(selected)
|
|
||||||
.alpha(dismissContentAlpha)
|
|
||||||
.combinedClickable(
|
|
||||||
onClick = onClick,
|
|
||||||
onLongClick = onLongClick,
|
|
||||||
)
|
|
||||||
.padding(start = 16.dp, top = 12.dp, end = 8.dp, bottom = 12.dp),
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(6.dp),
|
|
||||||
) {
|
) {
|
||||||
Row(
|
var textHeight by remember { mutableIntStateOf(0) }
|
||||||
horizontalArrangement = Arrangement.spacedBy(2.dp),
|
if (!read) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
Icon(
|
||||||
) {
|
imageVector = Icons.Filled.Circle,
|
||||||
var textHeight by remember { mutableIntStateOf(0) }
|
contentDescription = stringResource(R.string.unread),
|
||||||
if (!read) {
|
modifier = Modifier
|
||||||
Icon(
|
.height(8.dp)
|
||||||
imageVector = Icons.Filled.Circle,
|
.padding(end = 4.dp),
|
||||||
contentDescription = stringResource(R.string.unread),
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier
|
|
||||||
.height(8.dp)
|
|
||||||
.padding(end = 4.dp),
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (bookmark) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Filled.Bookmark,
|
|
||||||
contentDescription = stringResource(R.string.action_filter_bookmarked),
|
|
||||||
modifier = Modifier
|
|
||||||
.sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }),
|
|
||||||
tint = MaterialTheme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
text = title,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
color = LocalContentColor.current.copy(alpha = textAlpha),
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
onTextLayout = { textHeight = it.size.height },
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (bookmark) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Bookmark,
|
||||||
|
contentDescription = stringResource(R.string.action_filter_bookmarked),
|
||||||
|
modifier = Modifier
|
||||||
|
.sizeIn(maxHeight = with(LocalDensity.current) { textHeight.toDp() - 2.dp }),
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = LocalContentColor.current.copy(alpha = textAlpha),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
onTextLayout = { textHeight = it.size.height },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
ProvideTextStyle(
|
ProvideTextStyle(
|
||||||
value = MaterialTheme.typography.bodyMedium.copy(
|
value = MaterialTheme.typography.bodyMedium.copy(
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
color = LocalContentColor.current.copy(alpha = textSubtitleAlpha),
|
color = LocalContentColor.current.copy(alpha = textSubtitleAlpha),
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
if (date != null) {
|
if (date != null) {
|
||||||
Text(
|
Text(
|
||||||
text = date,
|
text = date,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
if (readProgress != null || scanlator != null) DotSeparatorText()
|
if (readProgress != null || scanlator != null) DotSeparatorText()
|
||||||
}
|
}
|
||||||
if (readProgress != null) {
|
if (readProgress != null) {
|
||||||
Text(
|
Text(
|
||||||
text = readProgress,
|
text = readProgress,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.alpha(ReadItemAlpha),
|
modifier = Modifier.alpha(ReadItemAlpha),
|
||||||
)
|
)
|
||||||
if (scanlator != null) DotSeparatorText()
|
if (scanlator != null) DotSeparatorText()
|
||||||
}
|
}
|
||||||
if (scanlator != null) {
|
if (scanlator != null) {
|
||||||
Text(
|
Text(
|
||||||
text = scanlator,
|
text = scanlator,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onDownloadClick != null) {
|
|
||||||
ChapterDownloadIndicator(
|
|
||||||
enabled = downloadIndicatorEnabled,
|
|
||||||
modifier = Modifier.padding(start = 4.dp),
|
|
||||||
downloadStateProvider = downloadStateProvider,
|
|
||||||
downloadProgressProvider = downloadProgressProvider,
|
|
||||||
onClick = onDownloadClick,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
)
|
if (onDownloadClick != null) {
|
||||||
|
ChapterDownloadIndicator(
|
||||||
|
enabled = downloadIndicatorEnabled,
|
||||||
|
modifier = Modifier.padding(start = 4.dp),
|
||||||
|
downloadStateProvider = downloadStateProvider,
|
||||||
|
downloadProgressProvider = downloadProgressProvider,
|
||||||
|
onClick = onDownloadClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
private fun getSwipeAction(
|
||||||
private fun SwipeBackgroundIcon(
|
action: LibraryPreferences.ChapterSwipeAction,
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
tint: Color,
|
|
||||||
swipeAction: LibraryPreferences.ChapterSwipeAction,
|
|
||||||
read: Boolean,
|
read: Boolean,
|
||||||
bookmark: Boolean,
|
bookmark: Boolean,
|
||||||
downloadState: Download.State,
|
downloadState: Download.State,
|
||||||
) {
|
background: Color,
|
||||||
val imageVector = when (swipeAction) {
|
onSwipe: () -> Unit,
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleRead -> {
|
): me.saket.swipe.SwipeAction? {
|
||||||
if (!read) {
|
return when (action) {
|
||||||
Icons.Outlined.Done
|
LibraryPreferences.ChapterSwipeAction.ToggleRead -> swipeAction(
|
||||||
} else {
|
icon = if (!read) Icons.Outlined.Done else Icons.Outlined.RemoveDone,
|
||||||
Icons.Outlined.RemoveDone
|
background = background,
|
||||||
}
|
isUndo = read,
|
||||||
}
|
onSwipe = onSwipe,
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> {
|
)
|
||||||
if (!bookmark) {
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark -> swipeAction(
|
||||||
Icons.Outlined.BookmarkAdd
|
icon = if (!bookmark) Icons.Outlined.BookmarkAdd else Icons.Outlined.BookmarkRemove,
|
||||||
} else {
|
background = background,
|
||||||
Icons.Outlined.BookmarkRemove
|
isUndo = bookmark,
|
||||||
}
|
onSwipe = onSwipe,
|
||||||
}
|
)
|
||||||
LibraryPreferences.ChapterSwipeAction.Download -> {
|
LibraryPreferences.ChapterSwipeAction.Download -> swipeAction(
|
||||||
when (downloadState) {
|
icon = when (downloadState) {
|
||||||
Download.State.NOT_DOWNLOADED,
|
Download.State.NOT_DOWNLOADED, Download.State.ERROR -> Icons.Outlined.Download
|
||||||
Download.State.ERROR,
|
Download.State.QUEUE, Download.State.DOWNLOADING -> Icons.Outlined.FileDownloadOff
|
||||||
-> { Icons.Outlined.Download }
|
Download.State.DOWNLOADED -> Icons.Outlined.Delete
|
||||||
Download.State.QUEUE,
|
},
|
||||||
Download.State.DOWNLOADING,
|
background = background,
|
||||||
-> { Icons.Outlined.FileDownloadOff }
|
onSwipe = onSwipe,
|
||||||
Download.State.DOWNLOADED -> { Icons.Outlined.Delete }
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled -> null
|
LibraryPreferences.ChapterSwipeAction.Disabled -> null
|
||||||
}
|
}
|
||||||
imageVector?.let {
|
|
||||||
Icon(
|
|
||||||
modifier = modifier,
|
|
||||||
imageVector = imageVector,
|
|
||||||
tint = tint,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun swipeAction(
|
||||||
|
onSwipe: () -> Unit,
|
||||||
|
icon: ImageVector,
|
||||||
|
background: Color,
|
||||||
|
isUndo: Boolean = false,
|
||||||
|
): me.saket.swipe.SwipeAction {
|
||||||
|
return me.saket.swipe.SwipeAction(
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.padding(16.dp),
|
||||||
|
imageVector = icon,
|
||||||
|
tint = contentColorFor(background),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
background = background,
|
||||||
|
onSwipe = onSwipe,
|
||||||
|
isUndo = isUndo,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val swipeActionThreshold = 56.dp
|
||||||
|
@ -2,13 +2,11 @@ package eu.kanade.presentation.manga.components
|
|||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
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.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.SelectAll
|
import androidx.compose.material.icons.outlined.SelectAll
|
||||||
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
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -29,6 +27,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
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.DownloadDropdownMenu
|
import eu.kanade.presentation.components.DownloadDropdownMenu
|
||||||
|
import eu.kanade.presentation.components.UpIcon
|
||||||
import eu.kanade.presentation.manga.DownloadAction
|
import eu.kanade.presentation.manga.DownloadAction
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import tachiyomi.presentation.core.theme.active
|
import tachiyomi.presentation.core.theme.active
|
||||||
@ -67,10 +66,7 @@ fun MangaToolbar(
|
|||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBackClicked) {
|
IconButton(onClick = onBackClicked) {
|
||||||
Icon(
|
UpIcon(Icons.Outlined.Close.takeIf { isActionMode })
|
||||||
imageVector = if (isActionMode) Icons.Outlined.Close else Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
|
@ -2,15 +2,12 @@ package eu.kanade.presentation.more.settings
|
|||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.presentation.components.UpIcon
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -27,10 +24,7 @@ fun PreferenceScaffold(
|
|||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
if (onBackPressed != null) {
|
if (onBackPressed != null) {
|
||||||
IconButton(onClick = onBackPressed) {
|
IconButton(onClick = onBackPressed) {
|
||||||
Icon(
|
UpIcon()
|
||||||
imageVector = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -28,6 +28,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
|
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
@ -281,8 +281,8 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
title = stringResource(R.string.pref_chapter_swipe),
|
title = stringResource(R.string.pref_chapter_swipe),
|
||||||
preferenceItems = listOf(
|
preferenceItems = listOf(
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.swipeEndAction(),
|
pref = libraryPreferences.swipeToStartAction(),
|
||||||
title = stringResource(R.string.pref_chapter_swipe_end),
|
title = stringResource(R.string.pref_chapter_swipe_start),
|
||||||
entries = mapOf(
|
entries = mapOf(
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.disabled),
|
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.disabled),
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
||||||
@ -291,8 +291,8 @@ object SettingsLibraryScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.ListPreference(
|
Preference.PreferenceItem.ListPreference(
|
||||||
pref = libraryPreferences.swipeStartAction(),
|
pref = libraryPreferences.swipeToEndAction(),
|
||||||
title = stringResource(R.string.pref_chapter_swipe_start),
|
title = stringResource(R.string.pref_chapter_swipe_end),
|
||||||
entries = mapOf(
|
entries = mapOf(
|
||||||
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.disabled),
|
LibraryPreferences.ChapterSwipeAction.Disabled to stringResource(R.string.disabled),
|
||||||
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
LibraryPreferences.ChapterSwipeAction.ToggleBookmark to stringResource(R.string.action_bookmark),
|
||||||
|
@ -4,11 +4,11 @@ import androidx.annotation.StringRes
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
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.ChromeReaderMode
|
import androidx.compose.material.icons.outlined.ChromeReaderMode
|
||||||
import androidx.compose.material.icons.outlined.Code
|
import androidx.compose.material.icons.outlined.Code
|
||||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||||
@ -20,7 +20,6 @@ import androidx.compose.material.icons.outlined.Search
|
|||||||
import androidx.compose.material.icons.outlined.Security
|
import androidx.compose.material.icons.outlined.Security
|
||||||
import androidx.compose.material.icons.outlined.SettingsBackupRestore
|
import androidx.compose.material.icons.outlined.SettingsBackupRestore
|
||||||
import androidx.compose.material.icons.outlined.Sync
|
import androidx.compose.material.icons.outlined.Sync
|
||||||
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
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -45,11 +44,12 @@ import cafe.adriel.voyager.navigator.Navigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
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.UpIcon
|
||||||
|
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||||
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
|
||||||
import eu.kanade.presentation.util.LocalBackPress
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import cafe.adriel.voyager.core.screen.Screen as VoyagerScreen
|
import cafe.adriel.voyager.core.screen.Screen as VoyagerScreen
|
||||||
|
|
||||||
@ -94,10 +94,7 @@ object SettingsMainScreen : Screen() {
|
|||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = backPress::invoke) {
|
IconButton(onClick = backPress::invoke) {
|
||||||
Icon(
|
UpIcon()
|
||||||
imageVector = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen
|
||||||
|
|
||||||
import android.content.res.Resources
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@ -17,7 +16,6 @@ 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
|
||||||
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.Close
|
import androidx.compose.material.icons.outlined.Close
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
@ -40,19 +38,21 @@ 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.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
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.ImeAction
|
||||||
import androidx.compose.ui.text.input.TextFieldValue
|
import androidx.compose.ui.text.input.TextFieldValue
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import eu.kanade.presentation.components.UpIcon
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.isLTR
|
|
||||||
import tachiyomi.presentation.core.components.material.Divider
|
import tachiyomi.presentation.core.components.material.Divider
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||||
@ -97,11 +97,7 @@ class SettingsSearchScreen : Screen() {
|
|||||||
val canPop = remember { navigator.canPop }
|
val canPop = remember { navigator.canPop }
|
||||||
if (canPop) {
|
if (canPop) {
|
||||||
IconButton(onClick = navigator::pop) {
|
IconButton(onClick = navigator::pop) {
|
||||||
Icon(
|
UpIcon()
|
||||||
imageVector = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -169,6 +165,8 @@ private fun SearchResult(
|
|||||||
) {
|
) {
|
||||||
if (searchKey.isEmpty()) return
|
if (searchKey.isEmpty()) return
|
||||||
|
|
||||||
|
val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr
|
||||||
|
|
||||||
val index = getIndex()
|
val index = getIndex()
|
||||||
val result by produceState<List<SearchResultItem>?>(initialValue = null, searchKey) {
|
val result by produceState<List<SearchResultItem>?>(initialValue = null, searchKey) {
|
||||||
value = index.asSequence()
|
value = index.asSequence()
|
||||||
@ -204,7 +202,7 @@ private fun SearchResult(
|
|||||||
SearchResultItem(
|
SearchResultItem(
|
||||||
route = settingsData.route,
|
route = settingsData.route,
|
||||||
title = p.title,
|
title = p.title,
|
||||||
breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle),
|
breadcrumbs = getLocalizedBreadcrumb(path = settingsData.title, node = categoryTitle, isLtr = isLtr),
|
||||||
highlightKey = p.title,
|
highlightKey = p.title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -269,11 +267,11 @@ private fun getIndex() = settingScreens
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLocalizedBreadcrumb(path: String, node: String?): String {
|
private fun getLocalizedBreadcrumb(path: String, node: String?, isLtr: Boolean): String {
|
||||||
return if (node == null) {
|
return if (node == null) {
|
||||||
path
|
path
|
||||||
} else {
|
} else {
|
||||||
if (Resources.getSystem().isLTR) {
|
if (isLtr) {
|
||||||
// This locale reads left to right.
|
// This locale reads left to right.
|
||||||
"$path > $node"
|
"$path > $node"
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen.about
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen.about
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen.about
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
@ -1,4 +1,4 @@
|
|||||||
package eu.kanade.presentation.more.settings.screen
|
package eu.kanade.presentation.more.settings.screen.advanced
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
@ -12,7 +12,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
import eu.kanade.presentation.more.settings.PreferenceScaffold
|
||||||
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import androidx.compose.foundation.horizontalScroll
|
import androidx.compose.foundation.horizontalScroll
|
||||||
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.LazyColumn
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
@ -39,7 +40,6 @@ import eu.kanade.tachiyomi.util.system.workManager
|
|||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.util.plus
|
import tachiyomi.presentation.core.util.plus
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Row
|
|||||||
import androidx.compose.foundation.layout.defaultMinSize
|
import androidx.compose.foundation.layout.defaultMinSize
|
||||||
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.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@ -28,7 +29,6 @@ import androidx.compose.ui.draw.clip
|
|||||||
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 eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.Divider
|
import tachiyomi.presentation.core.components.material.Divider
|
||||||
import tachiyomi.presentation.core.util.isScrolledToEnd
|
import tachiyomi.presentation.core.util.isScrolledToEnd
|
||||||
import tachiyomi.presentation.core.util.isScrolledToStart
|
import tachiyomi.presentation.core.util.isScrolledToStart
|
||||||
|
@ -3,6 +3,7 @@ package eu.kanade.presentation.more.stats
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
import androidx.compose.material.icons.outlined.CollectionsBookmark
|
||||||
@ -19,7 +20,6 @@ import eu.kanade.presentation.more.stats.components.StatsSection
|
|||||||
import eu.kanade.presentation.more.stats.data.StatsData
|
import eu.kanade.presentation.more.stats.data.StatsData
|
||||||
import eu.kanade.presentation.util.toDurationString
|
import eu.kanade.presentation.util.toDurationString
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
|
||||||
import tachiyomi.presentation.core.components.material.padding
|
import tachiyomi.presentation.core.components.material.padding
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
|
@ -0,0 +1,158 @@
|
|||||||
|
package eu.kanade.presentation.reader.settings
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.core.graphics.alpha
|
||||||
|
import androidx.core.graphics.blue
|
||||||
|
import androidx.core.graphics.green
|
||||||
|
import androidx.core.graphics.red
|
||||||
|
import eu.kanade.presentation.util.collectAsState
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||||
|
import tachiyomi.core.preference.getAndSet
|
||||||
|
import tachiyomi.presentation.core.components.CheckboxItem
|
||||||
|
import tachiyomi.presentation.core.components.SelectItem
|
||||||
|
import tachiyomi.presentation.core.components.SliderItem
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ColumnScope.ColorFilterPage(screenModel: ReaderSettingsScreenModel) {
|
||||||
|
val colorFilterModes = buildList {
|
||||||
|
addAll(
|
||||||
|
listOf(
|
||||||
|
R.string.label_default,
|
||||||
|
R.string.filter_mode_multiply,
|
||||||
|
R.string.filter_mode_screen,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
addAll(
|
||||||
|
listOf(
|
||||||
|
R.string.filter_mode_overlay,
|
||||||
|
R.string.filter_mode_lighten,
|
||||||
|
R.string.filter_mode_darken,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.map { stringResource(it) }
|
||||||
|
|
||||||
|
val customBrightness by screenModel.preferences.customBrightness().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_custom_brightness),
|
||||||
|
checked = customBrightness,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::customBrightness)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the brightness of the screen. Range is [-75, 100].
|
||||||
|
* From -75 to -1 a semi-transparent black view is shown at the top with the minimum brightness.
|
||||||
|
* From 1 to 100 it sets that value as brightness.
|
||||||
|
* 0 sets system brightness and hides the overlay.
|
||||||
|
*/
|
||||||
|
if (customBrightness) {
|
||||||
|
val customBrightnessValue by screenModel.preferences.customBrightnessValue().collectAsState()
|
||||||
|
SliderItem(
|
||||||
|
label = stringResource(R.string.pref_custom_brightness),
|
||||||
|
min = -75,
|
||||||
|
max = 100,
|
||||||
|
value = customBrightnessValue,
|
||||||
|
valueText = customBrightnessValue.toString(),
|
||||||
|
onChange = { screenModel.preferences.customBrightnessValue().set(it) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val colorFilter by screenModel.preferences.colorFilter().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_custom_color_filter),
|
||||||
|
checked = colorFilter,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::colorFilter)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if (colorFilter) {
|
||||||
|
val colorFilterValue by screenModel.preferences.colorFilterValue().collectAsState()
|
||||||
|
SliderItem(
|
||||||
|
label = stringResource(R.string.color_filter_r_value),
|
||||||
|
max = 255,
|
||||||
|
value = colorFilterValue.red,
|
||||||
|
valueText = colorFilterValue.red.toString(),
|
||||||
|
onChange = { newRValue ->
|
||||||
|
screenModel.preferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newRValue, RED_MASK, 16)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
SliderItem(
|
||||||
|
label = stringResource(R.string.color_filter_g_value),
|
||||||
|
max = 255,
|
||||||
|
value = colorFilterValue.green,
|
||||||
|
valueText = colorFilterValue.green.toString(),
|
||||||
|
onChange = { newGValue ->
|
||||||
|
screenModel.preferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newGValue, GREEN_MASK, 8)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
SliderItem(
|
||||||
|
label = stringResource(R.string.color_filter_b_value),
|
||||||
|
max = 255,
|
||||||
|
value = colorFilterValue.blue,
|
||||||
|
valueText = colorFilterValue.blue.toString(),
|
||||||
|
onChange = { newBValue ->
|
||||||
|
screenModel.preferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newBValue, BLUE_MASK, 0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
SliderItem(
|
||||||
|
label = stringResource(R.string.color_filter_a_value),
|
||||||
|
max = 255,
|
||||||
|
value = colorFilterValue.alpha,
|
||||||
|
valueText = colorFilterValue.alpha.toString(),
|
||||||
|
onChange = { newAValue ->
|
||||||
|
screenModel.preferences.colorFilterValue().getAndSet {
|
||||||
|
getColorValue(it, newAValue, ALPHA_MASK, 24)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val colorFilterMode by screenModel.preferences.colorFilterMode().collectAsState()
|
||||||
|
SelectItem(
|
||||||
|
label = stringResource(R.string.pref_color_filter_mode),
|
||||||
|
options = colorFilterModes.toTypedArray(),
|
||||||
|
selectedIndex = colorFilterMode,
|
||||||
|
) {
|
||||||
|
screenModel.preferences.colorFilterMode().set(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val grayscale by screenModel.preferences.grayscale().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_grayscale),
|
||||||
|
checked = grayscale,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::grayscale)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
val invertedColors by screenModel.preferences.invertedColors().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_inverted_colors),
|
||||||
|
checked = invertedColors,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::invertedColors)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getColorValue(currentColor: Int, color: Int, mask: Long, bitShift: Int): Int {
|
||||||
|
return (color shl bitShift) or (currentColor and mask.inv().toInt())
|
||||||
|
}
|
||||||
|
private const val ALPHA_MASK: Long = 0xFF000000
|
||||||
|
private const val RED_MASK: Long = 0x00FF0000
|
||||||
|
private const val GREEN_MASK: Long = 0x0000FF00
|
||||||
|
private const val BLUE_MASK: Long = 0x000000FF
|
@ -0,0 +1,96 @@
|
|||||||
|
package eu.kanade.presentation.reader.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import eu.kanade.presentation.util.collectAsState
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||||
|
import tachiyomi.presentation.core.components.CheckboxItem
|
||||||
|
import tachiyomi.presentation.core.components.HeadingItem
|
||||||
|
import tachiyomi.presentation.core.components.RadioItem
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ColumnScope.GeneralPage(screenModel: ReaderSettingsScreenModel) {
|
||||||
|
// TODO: show this in a nicer way
|
||||||
|
HeadingItem(stringResource(R.string.pref_reader_theme))
|
||||||
|
val readerTheme by screenModel.preferences.readerTheme().collectAsState()
|
||||||
|
listOf(
|
||||||
|
R.string.black_background to 1,
|
||||||
|
R.string.gray_background to 2,
|
||||||
|
R.string.white_background to 0,
|
||||||
|
R.string.automatic_background to 3,
|
||||||
|
).map { (titleRes, theme) ->
|
||||||
|
RadioItem(
|
||||||
|
label = stringResource(titleRes),
|
||||||
|
selected = readerTheme == theme,
|
||||||
|
onClick = { screenModel.preferences.readerTheme().set(theme) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val showPageNumber by screenModel.preferences.showPageNumber().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_show_page_number),
|
||||||
|
checked = showPageNumber,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::showPageNumber)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val fullscreen by screenModel.preferences.fullscreen().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_fullscreen),
|
||||||
|
checked = fullscreen,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::fullscreen)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: hide if there's no cutout
|
||||||
|
val cutoutShort by screenModel.preferences.cutoutShort().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_cutout_short),
|
||||||
|
checked = cutoutShort,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::cutoutShort)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val keepScreenOn by screenModel.preferences.keepScreenOn().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_keep_screen_on),
|
||||||
|
checked = keepScreenOn,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::keepScreenOn)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val readWithLongTap by screenModel.preferences.readWithLongTap().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_read_with_long_tap),
|
||||||
|
checked = readWithLongTap,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::readWithLongTap)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val alwaysShowChapterTransition by screenModel.preferences.alwaysShowChapterTransition().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_always_show_chapter_transition),
|
||||||
|
checked = alwaysShowChapterTransition,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::alwaysShowChapterTransition)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val pageTransitions by screenModel.preferences.pageTransitions().collectAsState()
|
||||||
|
CheckboxItem(
|
||||||
|
label = stringResource(R.string.pref_page_transitions),
|
||||||
|
checked = pageTransitions,
|
||||||
|
onClick = {
|
||||||
|
screenModel.togglePreference(ReaderPreferences::pageTransitions)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package eu.kanade.presentation.reader.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
|
import eu.kanade.presentation.components.TabbedDialog
|
||||||
|
import eu.kanade.presentation.components.TabbedDialogPaddings
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ReaderSettingsDialog(
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
onShowMenus: () -> Unit,
|
||||||
|
onHideMenus: () -> Unit,
|
||||||
|
screenModel: ReaderSettingsScreenModel,
|
||||||
|
) {
|
||||||
|
// TODO: undimming doesn't seem to work
|
||||||
|
val window = (LocalView.current.parent as? DialogWindowProvider)?.window
|
||||||
|
|
||||||
|
val tabTitles = listOf(
|
||||||
|
stringResource(R.string.pref_category_reading_mode),
|
||||||
|
stringResource(R.string.pref_category_general),
|
||||||
|
stringResource(R.string.custom_filter),
|
||||||
|
)
|
||||||
|
val pagerState = rememberPagerState { tabTitles.size }
|
||||||
|
|
||||||
|
LaunchedEffect(pagerState.currentPage) {
|
||||||
|
if (pagerState.currentPage == 2) {
|
||||||
|
window?.setDimAmount(0f)
|
||||||
|
onHideMenus()
|
||||||
|
} else {
|
||||||
|
window?.setDimAmount(0.75f)
|
||||||
|
onShowMenus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TabbedDialog(
|
||||||
|
onDismissRequest = {
|
||||||
|
onDismissRequest()
|
||||||
|
onShowMenus()
|
||||||
|
},
|
||||||
|
tabTitles = tabTitles,
|
||||||
|
pagerState = pagerState,
|
||||||
|
) { page ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = TabbedDialogPaddings.Vertical)
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
) {
|
||||||
|
when (page) {
|
||||||
|
0 -> ReadingModePage(screenModel)
|
||||||
|
1 -> GeneralPage(screenModel)
|
||||||
|
2 -> ColorFilterPage(screenModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package eu.kanade.presentation.reader.settings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun ColumnScope.ReadingModePage(screenModel: ReaderSettingsScreenModel) {
|
||||||
|
// TODO
|
||||||
|
}
|
@ -28,7 +28,6 @@ import eu.kanade.domain.ui.UiPreferences
|
|||||||
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
||||||
import eu.kanade.tachiyomi.crash.CrashActivity
|
import eu.kanade.tachiyomi.crash.CrashActivity
|
||||||
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
import eu.kanade.tachiyomi.crash.GlobalExceptionHandler
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
import eu.kanade.tachiyomi.data.coil.MangaCoverKeyer
|
||||||
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
import eu.kanade.tachiyomi.data.coil.MangaKeyer
|
||||||
@ -54,7 +53,6 @@ import org.acra.ktx.initAcra
|
|||||||
import org.acra.sender.HttpSender
|
import org.acra.sender.HttpSender
|
||||||
import org.conscrypt.Conscrypt
|
import org.conscrypt.Conscrypt
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
|
||||||
import tachiyomi.presentation.widget.TachiyomiWidgetManager
|
import tachiyomi.presentation.widget.TachiyomiWidgetManager
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -64,11 +62,9 @@ import java.security.Security
|
|||||||
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||||
|
|
||||||
private val basePreferences: BasePreferences by injectLazy()
|
private val basePreferences: BasePreferences by injectLazy()
|
||||||
private val libraryPreferences: LibraryPreferences by injectLazy()
|
|
||||||
private val networkPreferences: NetworkPreferences by injectLazy()
|
private val networkPreferences: NetworkPreferences by injectLazy()
|
||||||
|
|
||||||
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
private val disableIncognitoReceiver = DisableIncognitoReceiver()
|
||||||
private val chapterCache: ChapterCache by injectLazy()
|
|
||||||
|
|
||||||
@SuppressLint("LaunchActivityFromNotification")
|
@SuppressLint("LaunchActivityFromNotification")
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
@ -172,10 +168,6 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
|||||||
|
|
||||||
override fun onStop(owner: LifecycleOwner) {
|
override fun onStop(owner: LifecycleOwner) {
|
||||||
SecureActivityDelegate.onApplicationStopped()
|
SecureActivityDelegate.onApplicationStopped()
|
||||||
|
|
||||||
if (libraryPreferences.autoClearChapterCache().get()) {
|
|
||||||
chapterCache.clear()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPackageName(): String {
|
override fun getPackageName(): String {
|
||||||
|
@ -21,12 +21,11 @@ import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
|||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import eu.kanade.tachiyomi.util.system.workManager
|
import eu.kanade.tachiyomi.util.system.workManager
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.core.preference.getEnum
|
import tachiyomi.core.preference.getEnum
|
||||||
import tachiyomi.domain.backup.service.BackupPreferences
|
import tachiyomi.domain.backup.service.BackupPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
|
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
object Migrations {
|
object Migrations {
|
||||||
@ -350,12 +349,12 @@ object Migrations {
|
|||||||
remove(key)
|
remove(key)
|
||||||
|
|
||||||
val newValue = when (pref.get()) {
|
val newValue = when (pref.get()) {
|
||||||
1 -> TriStateFilter.ENABLED_IS
|
1 -> TriState.ENABLED_IS
|
||||||
2 -> TriStateFilter.ENABLED_NOT
|
2 -> TriState.ENABLED_NOT
|
||||||
else -> TriStateFilter.DISABLED
|
else -> TriState.DISABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceStore.getEnum("${key}_v2", TriStateFilter.DISABLED).set(newValue)
|
preferenceStore.getEnum("${key}_v2", TriState.DISABLED).set(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ data class BackupChapter(
|
|||||||
// chapterNumber is called number is 1.x
|
// chapterNumber is called number is 1.x
|
||||||
@ProtoNumber(9) var chapterNumber: Float = 0F,
|
@ProtoNumber(9) var chapterNumber: Float = 0F,
|
||||||
@ProtoNumber(10) var sourceOrder: Long = 0,
|
@ProtoNumber(10) var sourceOrder: Long = 0,
|
||||||
@ProtoNumber(11) var lastModifiedAt: Long? = null,
|
@ProtoNumber(11) var lastModifiedAt: Long = 0,
|
||||||
) {
|
) {
|
||||||
fun toChapterImpl(): Chapter {
|
fun toChapterImpl(): Chapter {
|
||||||
return Chapter.create().copy(
|
return Chapter.create().copy(
|
||||||
@ -39,7 +39,7 @@ data class BackupChapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val backupChapterMapper = { _: Long, _: Long, url: String, name: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, chapterNumber: Float, source_order: Long, dateFetch: Long, dateUpload: Long, lastModifiedAt: Long? ->
|
val backupChapterMapper = { _: Long, _: Long, url: String, name: String, scanlator: String?, read: Boolean, bookmark: Boolean, lastPageRead: Long, chapterNumber: Float, source_order: Long, dateFetch: Long, dateUpload: Long, lastModifiedAt: Long ->
|
||||||
BackupChapter(
|
BackupChapter(
|
||||||
url = url,
|
url = url,
|
||||||
name = name,
|
name = name,
|
||||||
|
@ -39,7 +39,8 @@ data class BackupManga(
|
|||||||
@ProtoNumber(103) var viewer_flags: Int? = null,
|
@ProtoNumber(103) var viewer_flags: Int? = null,
|
||||||
@ProtoNumber(104) var history: List<BackupHistory> = emptyList(),
|
@ProtoNumber(104) var history: List<BackupHistory> = emptyList(),
|
||||||
@ProtoNumber(105) var updateStrategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE,
|
@ProtoNumber(105) var updateStrategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE,
|
||||||
@ProtoNumber(106) var lastModifiedAt: Long? = 0,
|
@ProtoNumber(106) var lastModifiedAt: Long = 0,
|
||||||
|
@ProtoNumber(107) var favoriteModifiedAt: Long? = null,
|
||||||
) {
|
) {
|
||||||
fun getMangaImpl(): Manga {
|
fun getMangaImpl(): Manga {
|
||||||
return Manga.create().copy(
|
return Manga.create().copy(
|
||||||
@ -58,6 +59,7 @@ data class BackupManga(
|
|||||||
chapterFlags = this@BackupManga.chapterFlags.toLong(),
|
chapterFlags = this@BackupManga.chapterFlags.toLong(),
|
||||||
updateStrategy = this@BackupManga.updateStrategy,
|
updateStrategy = this@BackupManga.updateStrategy,
|
||||||
lastModifiedAt = this@BackupManga.lastModifiedAt,
|
lastModifiedAt = this@BackupManga.lastModifiedAt,
|
||||||
|
favoriteModifiedAt = this@BackupManga.favoriteModifiedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +94,7 @@ data class BackupManga(
|
|||||||
chapterFlags = manga.chapterFlags.toInt(),
|
chapterFlags = manga.chapterFlags.toInt(),
|
||||||
updateStrategy = manga.updateStrategy,
|
updateStrategy = manga.updateStrategy,
|
||||||
lastModifiedAt = manga.lastModifiedAt,
|
lastModifiedAt = manga.lastModifiedAt,
|
||||||
|
favoriteModifiedAt = manga.favoriteModifiedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ interface Chapter : SChapter, Serializable {
|
|||||||
|
|
||||||
var source_order: Int
|
var source_order: Int
|
||||||
|
|
||||||
var last_modified: Long?
|
var last_modified: Long
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Chapter.toDomainChapter(): DomainChapter? {
|
fun Chapter.toDomainChapter(): DomainChapter? {
|
||||||
|
@ -26,7 +26,7 @@ class ChapterImpl : Chapter {
|
|||||||
|
|
||||||
override var source_order: Int = 0
|
override var source_order: Int = 0
|
||||||
|
|
||||||
override var last_modified: Long? = null
|
override var last_modified: Long = 0
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
@ -7,9 +7,6 @@ import android.view.View
|
|||||||
import androidx.appcompat.view.ContextThemeWrapper
|
import androidx.appcompat.view.ContextThemeWrapper
|
||||||
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.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.outlined.ArrowBack
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
@ -21,7 +18,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
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.res.stringResource
|
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
@ -38,6 +34,7 @@ import androidx.preference.forEach
|
|||||||
import androidx.preference.getOnBindEditTextListener
|
import androidx.preference.getOnBindEditTextListener
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
|
import eu.kanade.presentation.components.UpIcon
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
|
import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
|
||||||
@ -62,10 +59,7 @@ class SourcePreferencesScreen(val sourceId: Long) : Screen() {
|
|||||||
title = { Text(text = Injekt.get<SourceManager>().getOrStub(sourceId).toString()) },
|
title = { Text(text = Injekt.get<SourceManager>().getOrStub(sourceId).toString()) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = navigator::pop) {
|
IconButton(onClick = navigator::pop) {
|
||||||
Icon(
|
UpIcon()
|
||||||
imageVector = Icons.Outlined.ArrowBack,
|
|
||||||
contentDescription = stringResource(R.string.abc_action_bar_up_description),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollBehavior = it,
|
scrollBehavior = it,
|
||||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.browse.migration
|
|||||||
import eu.kanade.domain.manga.model.hasCustomCover
|
import eu.kanade.domain.manga.model.hasCustomCover
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
@ -12,15 +13,18 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
|
|
||||||
object MigrationFlags {
|
object MigrationFlags {
|
||||||
|
|
||||||
private const val CHAPTERS = 0b0001
|
private const val CHAPTERS = 0b00001
|
||||||
private const val CATEGORIES = 0b0010
|
private const val CATEGORIES = 0b00010
|
||||||
private const val TRACK = 0b0100
|
private const val TRACK = 0b00100
|
||||||
private const val CUSTOM_COVER = 0b1000
|
private const val CUSTOM_COVER = 0b01000
|
||||||
|
private const val DELETE_DOWNLOADED = 0b10000
|
||||||
|
|
||||||
private val coverCache: CoverCache by injectLazy()
|
private val coverCache: CoverCache by injectLazy()
|
||||||
private val getTracks: GetTracks = Injekt.get()
|
private val getTracks: GetTracks = Injekt.get()
|
||||||
|
private val downloadCache: DownloadCache by injectLazy()
|
||||||
|
|
||||||
val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_COVER)
|
val flags get() = arrayOf(CHAPTERS, CATEGORIES, TRACK, CUSTOM_COVER, DELETE_DOWNLOADED)
|
||||||
|
private var enableFlags = emptyList<Int>().toMutableList()
|
||||||
|
|
||||||
fun hasChapters(value: Int): Boolean {
|
fun hasChapters(value: Int): Boolean {
|
||||||
return value and CHAPTERS != 0
|
return value and CHAPTERS != 0
|
||||||
@ -38,23 +42,36 @@ object MigrationFlags {
|
|||||||
return value and CUSTOM_COVER != 0
|
return value and CUSTOM_COVER != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasDeleteDownloaded(value: Int): Boolean {
|
||||||
|
return value and DELETE_DOWNLOADED != 0
|
||||||
|
}
|
||||||
|
|
||||||
fun getEnabledFlagsPositions(value: Int): List<Int> {
|
fun getEnabledFlagsPositions(value: Int): List<Int> {
|
||||||
return flags.mapIndexedNotNull { index, flag -> if (value and flag != 0) index else null }
|
return flags.mapIndexedNotNull { index, flag -> if (value and flag != 0) index else null }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFlagsFromPositions(positions: Array<Int>): Int {
|
fun getFlagsFromPositions(positions: Array<Int>): Int {
|
||||||
return positions.fold(0) { accumulated, position -> accumulated or (1 shl position) }
|
val fold = positions.fold(0) { accumulated, position -> accumulated or enableFlags[position] }
|
||||||
|
enableFlags.clear()
|
||||||
|
return fold
|
||||||
}
|
}
|
||||||
|
|
||||||
fun titles(manga: Manga?): Array<Int> {
|
fun titles(manga: Manga?): Array<Int> {
|
||||||
|
enableFlags.add(CHAPTERS)
|
||||||
|
enableFlags.add(CATEGORIES)
|
||||||
val titles = arrayOf(R.string.chapters, R.string.categories).toMutableList()
|
val titles = arrayOf(R.string.chapters, R.string.categories).toMutableList()
|
||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
if (runBlocking { getTracks.await(manga.id) }.isNotEmpty()) {
|
if (runBlocking { getTracks.await(manga.id) }.isNotEmpty()) {
|
||||||
titles.add(R.string.track)
|
titles.add(R.string.track)
|
||||||
|
enableFlags.add(TRACK)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (manga.hasCustomCover(coverCache)) {
|
if (manga.hasCustomCover(coverCache)) {
|
||||||
titles.add(R.string.custom_cover)
|
titles.add(R.string.custom_cover)
|
||||||
|
enableFlags.add(CUSTOM_COVER)
|
||||||
|
}
|
||||||
|
if (downloadCache.getDownloadCount(manga) > 0) {
|
||||||
|
titles.add(R.string.delete_downloaded)
|
||||||
|
enableFlags.add(DELETE_DOWNLOADED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return titles.toTypedArray()
|
return titles.toTypedArray()
|
||||||
|
@ -34,6 +34,7 @@ import eu.kanade.domain.manga.model.hasCustomCover
|
|||||||
import eu.kanade.domain.manga.model.toSManga
|
import eu.kanade.domain.manga.model.toSManga
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
import eu.kanade.tachiyomi.data.track.EnhancedTrackService
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
@ -161,6 +162,7 @@ internal fun MigrateDialog(
|
|||||||
|
|
||||||
internal class MigrateDialogScreenModel(
|
internal class MigrateDialogScreenModel(
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
|
private val downloadManager: DownloadManager = Injekt.get(),
|
||||||
private val updateManga: UpdateManga = Injekt.get(),
|
private val updateManga: UpdateManga = Injekt.get(),
|
||||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||||
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
private val syncChaptersWithSource: SyncChaptersWithSource = Injekt.get(),
|
||||||
@ -219,6 +221,7 @@ internal class MigrateDialogScreenModel(
|
|||||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
val migrateCategories = MigrationFlags.hasCategories(flags)
|
||||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
val migrateTracks = MigrationFlags.hasTracks(flags)
|
||||||
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
val migrateCustomCover = MigrationFlags.hasCustomCover(flags)
|
||||||
|
val deleteDownloaded = MigrationFlags.hasDeleteDownloaded(flags)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
syncChaptersWithSource.await(sourceChapters, newManga, newSource)
|
syncChaptersWithSource.await(sourceChapters, newManga, newSource)
|
||||||
@ -283,6 +286,13 @@ internal class MigrateDialogScreenModel(
|
|||||||
insertTrack.awaitAll(tracks)
|
insertTrack.awaitAll(tracks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete downloaded
|
||||||
|
if (deleteDownloaded) {
|
||||||
|
if (oldSource != null) {
|
||||||
|
downloadManager.deleteManga(oldManga, oldSource)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (replace) {
|
if (replace) {
|
||||||
updateManga.await(MangaUpdate(oldManga.id, favorite = false, dateAdded = 0))
|
updateManga.await(MangaUpdate(oldManga.id, favorite = false, dateAdded = 0))
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -15,18 +16,17 @@ import androidx.compose.ui.Modifier
|
|||||||
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 eu.kanade.presentation.components.AdaptiveSheet
|
import eu.kanade.presentation.components.AdaptiveSheet
|
||||||
import eu.kanade.presentation.components.SelectItem
|
|
||||||
import eu.kanade.presentation.components.TriStateItem
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.presentation.core.components.CheckboxItem
|
import tachiyomi.presentation.core.components.CheckboxItem
|
||||||
import tachiyomi.presentation.core.components.CollapsibleBox
|
import tachiyomi.presentation.core.components.CollapsibleBox
|
||||||
import tachiyomi.presentation.core.components.HeadingItem
|
import tachiyomi.presentation.core.components.HeadingItem
|
||||||
import tachiyomi.presentation.core.components.LazyColumn
|
import tachiyomi.presentation.core.components.SelectItem
|
||||||
import tachiyomi.presentation.core.components.SortItem
|
import tachiyomi.presentation.core.components.SortItem
|
||||||
import tachiyomi.presentation.core.components.TextItem
|
import tachiyomi.presentation.core.components.TextItem
|
||||||
|
import tachiyomi.presentation.core.components.TriStateItem
|
||||||
import tachiyomi.presentation.core.components.material.Button
|
import tachiyomi.presentation.core.components.material.Button
|
||||||
import tachiyomi.presentation.core.components.material.Divider
|
import tachiyomi.presentation.core.components.material.Divider
|
||||||
|
|
||||||
@ -164,19 +164,19 @@ private fun FilterItem(filter: Filter<*>, onUpdate: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Int.toTriStateFilter(): TriStateFilter {
|
private fun Int.toTriStateFilter(): TriState {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
Filter.TriState.STATE_IGNORE -> TriStateFilter.DISABLED
|
Filter.TriState.STATE_IGNORE -> TriState.DISABLED
|
||||||
Filter.TriState.STATE_INCLUDE -> TriStateFilter.ENABLED_IS
|
Filter.TriState.STATE_INCLUDE -> TriState.ENABLED_IS
|
||||||
Filter.TriState.STATE_EXCLUDE -> TriStateFilter.ENABLED_NOT
|
Filter.TriState.STATE_EXCLUDE -> TriState.ENABLED_NOT
|
||||||
else -> throw IllegalStateException("Unknown TriState state: $this")
|
else -> throw IllegalStateException("Unknown TriState state: $this")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TriStateFilter.toTriStateInt(): Int {
|
private fun TriState.toTriStateInt(): Int {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
TriStateFilter.DISABLED -> Filter.TriState.STATE_IGNORE
|
TriState.DISABLED -> Filter.TriState.STATE_IGNORE
|
||||||
TriStateFilter.ENABLED_IS -> Filter.TriState.STATE_INCLUDE
|
TriState.ENABLED_IS -> Filter.TriState.STATE_INCLUDE
|
||||||
TriStateFilter.ENABLED_NOT -> Filter.TriState.STATE_EXCLUDE
|
TriState.ENABLED_NOT -> Filter.TriState.STATE_EXCLUDE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import tachiyomi.core.preference.CheckboxState
|
import tachiyomi.core.preference.CheckboxState
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.core.util.lang.launchNonCancellable
|
import tachiyomi.core.util.lang.launchNonCancellable
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
@ -57,7 +58,6 @@ import tachiyomi.domain.library.service.LibraryPreferences
|
|||||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.MangaUpdate
|
import tachiyomi.domain.manga.model.MangaUpdate
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import tachiyomi.domain.manga.model.applyFilter
|
import tachiyomi.domain.manga.model.applyFilter
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.domain.track.interactor.GetTracksPerManga
|
import tachiyomi.domain.track.interactor.GetTracksPerManga
|
||||||
@ -153,7 +153,7 @@ class LibraryScreenModel(
|
|||||||
prefs.filterBookmarked,
|
prefs.filterBookmarked,
|
||||||
prefs.filterCompleted,
|
prefs.filterCompleted,
|
||||||
) + trackFilter.values
|
) + trackFilter.values
|
||||||
).any { it != TriStateFilter.DISABLED }
|
).any { it != TriState.DISABLED }
|
||||||
}
|
}
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.onEach {
|
.onEach {
|
||||||
@ -169,12 +169,12 @@ class LibraryScreenModel(
|
|||||||
*/
|
*/
|
||||||
private suspend fun LibraryMap.applyFilters(
|
private suspend fun LibraryMap.applyFilters(
|
||||||
trackMap: Map<Long, List<Long>>,
|
trackMap: Map<Long, List<Long>>,
|
||||||
loggedInTrackServices: Map<Long, TriStateFilter>,
|
loggedInTrackServices: Map<Long, TriState>,
|
||||||
): LibraryMap {
|
): LibraryMap {
|
||||||
val prefs = getLibraryItemPreferencesFlow().first()
|
val prefs = getLibraryItemPreferencesFlow().first()
|
||||||
val downloadedOnly = prefs.globalFilterDownloaded
|
val downloadedOnly = prefs.globalFilterDownloaded
|
||||||
val filterDownloaded =
|
val filterDownloaded =
|
||||||
if (downloadedOnly) TriStateFilter.ENABLED_IS else prefs.filterDownloaded
|
if (downloadedOnly) TriState.ENABLED_IS else prefs.filterDownloaded
|
||||||
val filterUnread = prefs.filterUnread
|
val filterUnread = prefs.filterUnread
|
||||||
val filterStarted = prefs.filterStarted
|
val filterStarted = prefs.filterStarted
|
||||||
val filterBookmarked = prefs.filterBookmarked
|
val filterBookmarked = prefs.filterBookmarked
|
||||||
@ -182,8 +182,8 @@ class LibraryScreenModel(
|
|||||||
|
|
||||||
val isNotLoggedInAnyTrack = loggedInTrackServices.isEmpty()
|
val isNotLoggedInAnyTrack = loggedInTrackServices.isEmpty()
|
||||||
|
|
||||||
val excludedTracks = loggedInTrackServices.mapNotNull { if (it.value == TriStateFilter.ENABLED_NOT) it.key else null }
|
val excludedTracks = loggedInTrackServices.mapNotNull { if (it.value == TriState.ENABLED_NOT) it.key else null }
|
||||||
val includedTracks = loggedInTrackServices.mapNotNull { if (it.value == TriStateFilter.ENABLED_IS) it.key else null }
|
val includedTracks = loggedInTrackServices.mapNotNull { if (it.value == TriState.ENABLED_IS) it.key else null }
|
||||||
val trackFiltersIsIgnored = includedTracks.isEmpty() && excludedTracks.isEmpty()
|
val trackFiltersIsIgnored = includedTracks.isEmpty() && excludedTracks.isEmpty()
|
||||||
|
|
||||||
val filterFnDownloaded: (LibraryItem) -> Boolean = {
|
val filterFnDownloaded: (LibraryItem) -> Boolean = {
|
||||||
@ -308,11 +308,11 @@ class LibraryScreenModel(
|
|||||||
localBadge = it[1] as Boolean,
|
localBadge = it[1] as Boolean,
|
||||||
languageBadge = it[2] as Boolean,
|
languageBadge = it[2] as Boolean,
|
||||||
globalFilterDownloaded = it[3] as Boolean,
|
globalFilterDownloaded = it[3] as Boolean,
|
||||||
filterDownloaded = it[4] as TriStateFilter,
|
filterDownloaded = it[4] as TriState,
|
||||||
filterUnread = it[5] as TriStateFilter,
|
filterUnread = it[5] as TriState,
|
||||||
filterStarted = it[6] as TriStateFilter,
|
filterStarted = it[6] as TriState,
|
||||||
filterBookmarked = it[7] as TriStateFilter,
|
filterBookmarked = it[7] as TriState,
|
||||||
filterCompleted = it[8] as TriStateFilter,
|
filterCompleted = it[8] as TriState,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -365,7 +365,7 @@ class LibraryScreenModel(
|
|||||||
*
|
*
|
||||||
* @return map of track id with the filter value
|
* @return map of track id with the filter value
|
||||||
*/
|
*/
|
||||||
private fun getTrackingFilterFlow(): Flow<Map<Long, TriStateFilter>> {
|
private fun getTrackingFilterFlow(): Flow<Map<Long, TriState>> {
|
||||||
val loggedServices = trackManager.services.filter { it.isLogged }
|
val loggedServices = trackManager.services.filter { it.isLogged }
|
||||||
return if (loggedServices.isNotEmpty()) {
|
return if (loggedServices.isNotEmpty()) {
|
||||||
val prefFlows = loggedServices
|
val prefFlows = loggedServices
|
||||||
@ -670,11 +670,11 @@ class LibraryScreenModel(
|
|||||||
val languageBadge: Boolean,
|
val languageBadge: Boolean,
|
||||||
|
|
||||||
val globalFilterDownloaded: Boolean,
|
val globalFilterDownloaded: Boolean,
|
||||||
val filterDownloaded: TriStateFilter,
|
val filterDownloaded: TriState,
|
||||||
val filterUnread: TriStateFilter,
|
val filterUnread: TriState,
|
||||||
val filterStarted: TriStateFilter,
|
val filterStarted: TriState,
|
||||||
val filterBookmarked: TriStateFilter,
|
val filterBookmarked: TriState,
|
||||||
val filterCompleted: TriStateFilter,
|
val filterCompleted: TriState,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
@ -6,6 +6,7 @@ import eu.kanade.domain.base.BasePreferences
|
|||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.util.preference.toggle
|
import eu.kanade.tachiyomi.util.preference.toggle
|
||||||
import tachiyomi.core.preference.Preference
|
import tachiyomi.core.preference.Preference
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.core.preference.getAndSet
|
import tachiyomi.core.preference.getAndSet
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.domain.category.interactor.SetDisplayMode
|
import tachiyomi.domain.category.interactor.SetDisplayMode
|
||||||
@ -14,7 +15,6 @@ import tachiyomi.domain.category.model.Category
|
|||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
import tachiyomi.domain.library.model.LibrarySort
|
import tachiyomi.domain.library.model.LibrarySort
|
||||||
import tachiyomi.domain.library.service.LibraryPreferences
|
import tachiyomi.domain.library.service.LibraryPreferences
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class LibrarySettingsScreenModel(
|
|||||||
preference(libraryPreferences).toggle()
|
preference(libraryPreferences).toggle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriStateFilter>) {
|
fun toggleFilter(preference: (LibraryPreferences) -> Preference<TriState>) {
|
||||||
preference(libraryPreferences).getAndSet {
|
preference(libraryPreferences).getAndSet {
|
||||||
it.next()
|
it.next()
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ import eu.kanade.presentation.util.collectAsState
|
|||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.Migrations
|
import eu.kanade.tachiyomi.Migrations
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
||||||
@ -105,6 +106,7 @@ class MainActivity : BaseActivity() {
|
|||||||
private val preferences: BasePreferences by injectLazy()
|
private val preferences: BasePreferences by injectLazy()
|
||||||
|
|
||||||
private val downloadCache: DownloadCache by injectLazy()
|
private val downloadCache: DownloadCache by injectLazy()
|
||||||
|
private val chapterCache: ChapterCache by injectLazy()
|
||||||
|
|
||||||
// To be checked by splash screen. If true then splash screen will be removed.
|
// To be checked by splash screen. If true then splash screen will be removed.
|
||||||
var ready = false
|
var ready = false
|
||||||
@ -112,12 +114,14 @@ class MainActivity : BaseActivity() {
|
|||||||
private var navigator: Navigator? = null
|
private var navigator: Navigator? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
val isLaunch = savedInstanceState == null
|
||||||
|
|
||||||
// Prevent splash screen showing up on configuration changes
|
// Prevent splash screen showing up on configuration changes
|
||||||
val splashScreen = if (savedInstanceState == null) installSplashScreen() else null
|
val splashScreen = if (isLaunch) installSplashScreen() else null
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val didMigration = if (savedInstanceState == null) {
|
val didMigration = if (isLaunch) {
|
||||||
Migrations.upgrade(
|
Migrations.upgrade(
|
||||||
context = applicationContext,
|
context = applicationContext,
|
||||||
basePreferences = preferences,
|
basePreferences = preferences,
|
||||||
@ -149,7 +153,7 @@ class MainActivity : BaseActivity() {
|
|||||||
val downloadOnly by preferences.downloadedOnly().collectAsState()
|
val downloadOnly by preferences.downloadedOnly().collectAsState()
|
||||||
val indexing by downloadCache.isInitializing.collectAsState()
|
val indexing by downloadCache.isInitializing.collectAsState()
|
||||||
|
|
||||||
// Set statusbar color considering the top app state banner
|
// Set status bar color considering the top app state banner
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
val isSystemInDarkTheme = isSystemInDarkTheme()
|
val isSystemInDarkTheme = isSystemInDarkTheme()
|
||||||
val statusBarBackgroundColor = when {
|
val statusBarBackgroundColor = when {
|
||||||
@ -189,7 +193,7 @@ class MainActivity : BaseActivity() {
|
|||||||
LaunchedEffect(navigator) {
|
LaunchedEffect(navigator) {
|
||||||
this@MainActivity.navigator = navigator
|
this@MainActivity.navigator = navigator
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (isLaunch) {
|
||||||
// Set start screen
|
// Set start screen
|
||||||
handleIntentAction(intent, navigator)
|
handleIntentAction(intent, navigator)
|
||||||
|
|
||||||
@ -267,6 +271,10 @@ class MainActivity : BaseActivity() {
|
|||||||
elapsed <= SPLASH_MIN_DURATION || (!ready && elapsed <= SPLASH_MAX_DURATION)
|
elapsed <= SPLASH_MIN_DURATION || (!ready && elapsed <= SPLASH_MAX_DURATION)
|
||||||
}
|
}
|
||||||
setSplashScreenExitAnimation(splashScreen)
|
setSplashScreenExitAnimation(splashScreen)
|
||||||
|
|
||||||
|
if (isLaunch && libraryPreferences.autoClearChapterCache().get()) {
|
||||||
|
chapterCache.clear()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onProvideAssistContent(outContent: AssistContent) {
|
override fun onProvideAssistContent(outContent: AssistContent) {
|
||||||
@ -279,7 +287,7 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HandleOnNewIntent(context: Context, navigator: Navigator) {
|
private fun HandleOnNewIntent(context: Context, navigator: Navigator) {
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
callbackFlow<Intent> {
|
callbackFlow<Intent> {
|
||||||
val componentActivity = context as ComponentActivity
|
val componentActivity = context as ComponentActivity
|
||||||
|
@ -101,8 +101,8 @@ class MangaScreen(
|
|||||||
dateRelativeTime = screenModel.relativeTime,
|
dateRelativeTime = screenModel.relativeTime,
|
||||||
dateFormat = screenModel.dateFormat,
|
dateFormat = screenModel.dateFormat,
|
||||||
isTabletUi = isTabletUi(),
|
isTabletUi = isTabletUi(),
|
||||||
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
|
||||||
chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
|
chapterSwipeStartAction = screenModel.chapterSwipeStartAction,
|
||||||
|
chapterSwipeEndAction = screenModel.chapterSwipeEndAction,
|
||||||
onBackClicked = navigator::pop,
|
onBackClicked = navigator::pop,
|
||||||
onChapterClicked = { openChapter(context, it) },
|
onChapterClicked = { openChapter(context, it) },
|
||||||
onDownloadChapter = screenModel::runChapterDownloadActions.takeIf { !successState.source.isLocalOrStub() },
|
onDownloadChapter = screenModel::runChapterDownloadActions.takeIf { !successState.source.isLocalOrStub() },
|
||||||
|
@ -46,6 +46,7 @@ import kotlinx.coroutines.isActive
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.preference.CheckboxState
|
import tachiyomi.core.preference.CheckboxState
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.core.preference.mapAsCheckboxState
|
import tachiyomi.core.preference.mapAsCheckboxState
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.core.util.lang.launchNonCancellable
|
import tachiyomi.core.util.lang.launchNonCancellable
|
||||||
@ -67,7 +68,6 @@ import tachiyomi.domain.manga.interactor.GetDuplicateLibraryManga
|
|||||||
import tachiyomi.domain.manga.interactor.GetMangaWithChapters
|
import tachiyomi.domain.manga.interactor.GetMangaWithChapters
|
||||||
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
|
import tachiyomi.domain.manga.interactor.SetMangaChapterFlags
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
import tachiyomi.domain.manga.model.applyFilter
|
import tachiyomi.domain.manga.model.applyFilter
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
import tachiyomi.domain.track.interactor.GetTracks
|
||||||
@ -119,11 +119,11 @@ class MangaInfoScreenModel(
|
|||||||
private val allChapters: List<ChapterItem>?
|
private val allChapters: List<ChapterItem>?
|
||||||
get() = successState?.chapters
|
get() = successState?.chapters
|
||||||
|
|
||||||
private val filteredChapters: Sequence<ChapterItem>?
|
private val filteredChapters: List<ChapterItem>?
|
||||||
get() = successState?.processedChapters
|
get() = successState?.processedChapters
|
||||||
|
|
||||||
val chapterSwipeEndAction = libraryPreferences.swipeEndAction().get()
|
val chapterSwipeStartAction = libraryPreferences.swipeToEndAction().get()
|
||||||
val chapterSwipeStartAction = libraryPreferences.swipeStartAction().get()
|
val chapterSwipeEndAction = libraryPreferences.swipeToStartAction().get()
|
||||||
|
|
||||||
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
|
val relativeTime by uiPreferences.relativeTime().asState(coroutineScope)
|
||||||
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
val dateFormat by mutableStateOf(UiPreferences.dateFormat(uiPreferences.dateFormat().get()))
|
||||||
@ -576,7 +576,7 @@ class MangaInfoScreenModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getUnreadChapters(): List<Chapter> {
|
private fun getUnreadChapters(): List<Chapter> {
|
||||||
val chapterItems = if (skipFiltered) filteredChapters.orEmpty().toList() else allChapters.orEmpty()
|
val chapterItems = if (skipFiltered) filteredChapters.orEmpty() else allChapters.orEmpty()
|
||||||
return chapterItems
|
return chapterItems
|
||||||
.filter { (chapter, dlStatus) -> !chapter.read && dlStatus == Download.State.NOT_DOWNLOADED }
|
.filter { (chapter, dlStatus) -> !chapter.read && dlStatus == Download.State.NOT_DOWNLOADED }
|
||||||
.map { it.chapter }
|
.map { it.chapter }
|
||||||
@ -664,7 +664,7 @@ class MangaInfoScreenModel(
|
|||||||
|
|
||||||
fun markPreviousChapterRead(pointer: Chapter) {
|
fun markPreviousChapterRead(pointer: Chapter) {
|
||||||
val successState = successState ?: return
|
val successState = successState ?: return
|
||||||
val chapters = filteredChapters.orEmpty().map { it.chapter }.toList()
|
val chapters = filteredChapters.orEmpty().map { it.chapter }
|
||||||
val prevChapters = if (successState.manga.sortDescending()) chapters.asReversed() else chapters
|
val prevChapters = if (successState.manga.sortDescending()) chapters.asReversed() else chapters
|
||||||
val pointerPos = prevChapters.indexOf(pointer)
|
val pointerPos = prevChapters.indexOf(pointer)
|
||||||
if (pointerPos != -1) markChaptersRead(prevChapters.take(pointerPos), true)
|
if (pointerPos != -1) markChaptersRead(prevChapters.take(pointerPos), true)
|
||||||
@ -743,13 +743,13 @@ class MangaInfoScreenModel(
|
|||||||
* Sets the read filter and requests an UI update.
|
* Sets the read filter and requests an UI update.
|
||||||
* @param state whether to display only unread chapters or all chapters.
|
* @param state whether to display only unread chapters or all chapters.
|
||||||
*/
|
*/
|
||||||
fun setUnreadFilter(state: TriStateFilter) {
|
fun setUnreadFilter(state: TriState) {
|
||||||
val manga = successState?.manga ?: return
|
val manga = successState?.manga ?: return
|
||||||
|
|
||||||
val flag = when (state) {
|
val flag = when (state) {
|
||||||
TriStateFilter.DISABLED -> Manga.SHOW_ALL
|
TriState.DISABLED -> Manga.SHOW_ALL
|
||||||
TriStateFilter.ENABLED_IS -> Manga.CHAPTER_SHOW_UNREAD
|
TriState.ENABLED_IS -> Manga.CHAPTER_SHOW_UNREAD
|
||||||
TriStateFilter.ENABLED_NOT -> Manga.CHAPTER_SHOW_READ
|
TriState.ENABLED_NOT -> Manga.CHAPTER_SHOW_READ
|
||||||
}
|
}
|
||||||
coroutineScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
setMangaChapterFlags.awaitSetUnreadFilter(manga, flag)
|
setMangaChapterFlags.awaitSetUnreadFilter(manga, flag)
|
||||||
@ -760,13 +760,13 @@ class MangaInfoScreenModel(
|
|||||||
* Sets the download filter and requests an UI update.
|
* Sets the download filter and requests an UI update.
|
||||||
* @param state whether to display only downloaded chapters or all chapters.
|
* @param state whether to display only downloaded chapters or all chapters.
|
||||||
*/
|
*/
|
||||||
fun setDownloadedFilter(state: TriStateFilter) {
|
fun setDownloadedFilter(state: TriState) {
|
||||||
val manga = successState?.manga ?: return
|
val manga = successState?.manga ?: return
|
||||||
|
|
||||||
val flag = when (state) {
|
val flag = when (state) {
|
||||||
TriStateFilter.DISABLED -> Manga.SHOW_ALL
|
TriState.DISABLED -> Manga.SHOW_ALL
|
||||||
TriStateFilter.ENABLED_IS -> Manga.CHAPTER_SHOW_DOWNLOADED
|
TriState.ENABLED_IS -> Manga.CHAPTER_SHOW_DOWNLOADED
|
||||||
TriStateFilter.ENABLED_NOT -> Manga.CHAPTER_SHOW_NOT_DOWNLOADED
|
TriState.ENABLED_NOT -> Manga.CHAPTER_SHOW_NOT_DOWNLOADED
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutineScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
@ -778,13 +778,13 @@ class MangaInfoScreenModel(
|
|||||||
* Sets the bookmark filter and requests an UI update.
|
* Sets the bookmark filter and requests an UI update.
|
||||||
* @param state whether to display only bookmarked chapters or all chapters.
|
* @param state whether to display only bookmarked chapters or all chapters.
|
||||||
*/
|
*/
|
||||||
fun setBookmarkedFilter(state: TriStateFilter) {
|
fun setBookmarkedFilter(state: TriState) {
|
||||||
val manga = successState?.manga ?: return
|
val manga = successState?.manga ?: return
|
||||||
|
|
||||||
val flag = when (state) {
|
val flag = when (state) {
|
||||||
TriStateFilter.DISABLED -> Manga.SHOW_ALL
|
TriState.DISABLED -> Manga.SHOW_ALL
|
||||||
TriStateFilter.ENABLED_IS -> Manga.CHAPTER_SHOW_BOOKMARKED
|
TriState.ENABLED_IS -> Manga.CHAPTER_SHOW_BOOKMARKED
|
||||||
TriStateFilter.ENABLED_NOT -> Manga.CHAPTER_SHOW_NOT_BOOKMARKED
|
TriState.ENABLED_NOT -> Manga.CHAPTER_SHOW_NOT_BOOKMARKED
|
||||||
}
|
}
|
||||||
|
|
||||||
coroutineScope.launchNonCancellable {
|
coroutineScope.launchNonCancellable {
|
||||||
@ -987,8 +987,9 @@ sealed class MangaScreenState {
|
|||||||
val hasPromptedToAddBefore: Boolean = false,
|
val hasPromptedToAddBefore: Boolean = false,
|
||||||
) : MangaScreenState() {
|
) : MangaScreenState() {
|
||||||
|
|
||||||
val processedChapters: Sequence<ChapterItem>
|
val processedChapters by lazy {
|
||||||
get() = chapters.applyFilters(manga)
|
chapters.applyFilters(manga).toList()
|
||||||
|
}
|
||||||
|
|
||||||
val trackingAvailable: Boolean
|
val trackingAvailable: Boolean
|
||||||
get() = trackItems.isNotEmpty()
|
get() = trackItems.isNotEmpty()
|
||||||
|
@ -31,6 +31,7 @@ import androidx.compose.material3.CircularProgressIndicator
|
|||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@ -51,6 +52,7 @@ import eu.kanade.domain.base.BasePreferences
|
|||||||
import eu.kanade.domain.manga.model.orientationType
|
import eu.kanade.domain.manga.model.orientationType
|
||||||
import eu.kanade.presentation.reader.ChapterNavigator
|
import eu.kanade.presentation.reader.ChapterNavigator
|
||||||
import eu.kanade.presentation.reader.PageIndicatorText
|
import eu.kanade.presentation.reader.PageIndicatorText
|
||||||
|
import eu.kanade.presentation.reader.settings.ReaderSettingsDialog
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
@ -65,8 +67,8 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
|||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderColorFilterDialog
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet
|
import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsSheet
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderProgressIndicator
|
||||||
@ -235,13 +237,18 @@ class ReaderActivity : BaseActivity() {
|
|||||||
readingModeToast?.cancel()
|
readingModeToast?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
viewModel.flushReadTimer()
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set menu visibility again on activity resume to apply immersive mode again if needed.
|
* Set menu visibility again on activity resume to apply immersive mode again if needed.
|
||||||
* Helps with rotations.
|
* Helps with rotations.
|
||||||
*/
|
*/
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
viewModel.setReadStartTime()
|
viewModel.restartReadTimer()
|
||||||
setMenuVisibility(viewModel.state.value.menuVisible, animate = false)
|
setMenuVisibility(viewModel.state.value.menuVisible, animate = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +391,8 @@ class ReaderActivity : BaseActivity() {
|
|||||||
|
|
||||||
binding.dialogRoot.setComposeContent {
|
binding.dialogRoot.setComposeContent {
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
|
val settingsScreenModel = remember { ReaderSettingsScreenModel() }
|
||||||
|
|
||||||
val onDismissRequest = viewModel::closeDialog
|
val onDismissRequest = viewModel::closeDialog
|
||||||
when (state.dialog) {
|
when (state.dialog) {
|
||||||
is ReaderViewModel.Dialog.Loading -> {
|
is ReaderViewModel.Dialog.Loading -> {
|
||||||
@ -401,14 +410,12 @@ class ReaderActivity : BaseActivity() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ReaderViewModel.Dialog.ColorFilter -> {
|
is ReaderViewModel.Dialog.Settings -> {
|
||||||
setMenuVisibility(false)
|
ReaderSettingsDialog(
|
||||||
ReaderColorFilterDialog(
|
onDismissRequest = onDismissRequest,
|
||||||
onDismissRequest = {
|
onShowMenus = { setMenuVisibility(true) },
|
||||||
onDismissRequest()
|
onHideMenus = { setMenuVisibility(false) },
|
||||||
setMenuVisibility(true)
|
screenModel = settingsScreenModel,
|
||||||
},
|
|
||||||
readerPreferences = viewModel.readerPreferences,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is ReaderViewModel.Dialog.PageActions -> {
|
is ReaderViewModel.Dialog.PageActions -> {
|
||||||
@ -541,7 +548,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settings sheet
|
// Settings sheet
|
||||||
with(binding.actionSettings) {
|
with(binding.actionSettingsLegacy) {
|
||||||
setTooltip(R.string.action_settings)
|
setTooltip(R.string.action_settings)
|
||||||
|
|
||||||
var readerSettingSheet: ReaderSettingsSheet? = null
|
var readerSettingSheet: ReaderSettingsSheet? = null
|
||||||
@ -551,13 +558,11 @@ class ReaderActivity : BaseActivity() {
|
|||||||
readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity).apply { show() }
|
readerSettingSheet = ReaderSettingsSheet(this@ReaderActivity).apply { show() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
with(binding.actionSettings) {
|
||||||
// Color filter sheet
|
setTooltip(R.string.action_settings)
|
||||||
with(binding.actionColorSettings) {
|
|
||||||
setTooltip(R.string.custom_filter)
|
|
||||||
|
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
viewModel.openColorFilterDialog()
|
viewModel.openSettingsDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -588,7 +593,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
* Sets the visibility of the menu according to [visible] and with an optional parameter to
|
* Sets the visibility of the menu according to [visible] and with an optional parameter to
|
||||||
* [animate] the views.
|
* [animate] the views.
|
||||||
*/
|
*/
|
||||||
fun setMenuVisibility(visible: Boolean, animate: Boolean = true) {
|
private fun setMenuVisibility(visible: Boolean, animate: Boolean = true) {
|
||||||
viewModel.showMenus(visible)
|
viewModel.showMenus(visible)
|
||||||
if (visible) {
|
if (visible) {
|
||||||
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
|
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
|
||||||
@ -793,7 +798,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
* Called from the viewer whenever a [page] is marked as active. It updates the values of the
|
* Called from the viewer whenever a [page] is marked as active. It updates the values of the
|
||||||
* bottom menu and delegates the change to the presenter.
|
* bottom menu and delegates the change to the presenter.
|
||||||
*/
|
*/
|
||||||
@SuppressLint("SetTextI18n")
|
|
||||||
fun onPageSelected(page: ReaderPage) {
|
fun onPageSelected(page: ReaderPage) {
|
||||||
viewModel.onPageSelected(page)
|
viewModel.onPageSelected(page)
|
||||||
}
|
}
|
||||||
@ -811,7 +815,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
* the viewer is reaching the beginning or end of a chapter or the transition page is active.
|
* the viewer is reaching the beginning or end of a chapter or the transition page is active.
|
||||||
*/
|
*/
|
||||||
fun requestPreloadChapter(chapter: ReaderChapter) {
|
fun requestPreloadChapter(chapter: ReaderChapter) {
|
||||||
lifecycleScope.launchIO { viewModel.preloadChapter(chapter) }
|
lifecycleScope.launchIO { viewModel.preload(chapter) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -898,7 +902,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
/**
|
/**
|
||||||
* Updates viewer inset depending on fullscreen reader preferences.
|
* Updates viewer inset depending on fullscreen reader preferences.
|
||||||
*/
|
*/
|
||||||
fun updateViewerInset(fullscreen: Boolean) {
|
private fun updateViewerInset(fullscreen: Boolean) {
|
||||||
viewModel.state.value.viewer?.getView()?.applyInsetter {
|
viewModel.state.value.viewer?.getView()?.applyInsetter {
|
||||||
if (!fullscreen) {
|
if (!fullscreen) {
|
||||||
type(navigationBars = true, statusBars = true) {
|
type(navigationBars = true, statusBars = true) {
|
||||||
|
@ -10,10 +10,8 @@ import eu.kanade.domain.chapter.model.toDbChapter
|
|||||||
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
|
||||||
import eu.kanade.domain.manga.model.orientationType
|
import eu.kanade.domain.manga.model.orientationType
|
||||||
import eu.kanade.domain.manga.model.readingModeType
|
import eu.kanade.domain.manga.model.readingModeType
|
||||||
import eu.kanade.domain.track.model.toDbTrack
|
import eu.kanade.domain.track.interactor.TrackChapter
|
||||||
import eu.kanade.domain.track.service.DelayedTrackingUpdateJob
|
|
||||||
import eu.kanade.domain.track.service.TrackPreferences
|
import eu.kanade.domain.track.service.TrackPreferences
|
||||||
import eu.kanade.domain.track.store.DelayedTrackingStore
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
|
||||||
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
|
||||||
@ -21,10 +19,10 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
|||||||
import eu.kanade.tachiyomi.data.saver.Image
|
import eu.kanade.tachiyomi.data.saver.Image
|
||||||
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
||||||
import eu.kanade.tachiyomi.data.saver.Location
|
import eu.kanade.tachiyomi.data.saver.Location
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
import eu.kanade.tachiyomi.ui.reader.model.InsertPage
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||||
@ -41,11 +39,8 @@ import eu.kanade.tachiyomi.util.lang.byteSize
|
|||||||
import eu.kanade.tachiyomi.util.lang.takeBytes
|
import eu.kanade.tachiyomi.util.lang.takeBytes
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
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 kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@ -56,7 +51,6 @@ import kotlinx.coroutines.flow.map
|
|||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
@ -75,8 +69,6 @@ import tachiyomi.domain.history.model.HistoryUpdate
|
|||||||
import tachiyomi.domain.manga.interactor.GetManga
|
import tachiyomi.domain.manga.interactor.GetManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import tachiyomi.domain.track.interactor.GetTracks
|
|
||||||
import tachiyomi.domain.track.interactor.InsertTrack
|
|
||||||
import tachiyomi.source.local.isLocal
|
import tachiyomi.source.local.isLocal
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -96,12 +88,10 @@ class ReaderViewModel(
|
|||||||
private val basePreferences: BasePreferences = Injekt.get(),
|
private val basePreferences: BasePreferences = Injekt.get(),
|
||||||
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
private val downloadPreferences: DownloadPreferences = Injekt.get(),
|
||||||
private val trackPreferences: TrackPreferences = Injekt.get(),
|
private val trackPreferences: TrackPreferences = Injekt.get(),
|
||||||
private val delayedTrackingStore: DelayedTrackingStore = Injekt.get(),
|
private val trackChapter: TrackChapter = 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 getNextChapters: GetNextChapters = Injekt.get(),
|
private val getNextChapters: GetNextChapters = Injekt.get(),
|
||||||
private val getTracks: GetTracks = Injekt.get(),
|
|
||||||
private val insertTrack: InsertTrack = Injekt.get(),
|
|
||||||
private val upsertHistory: UpsertHistory = Injekt.get(),
|
private val upsertHistory: UpsertHistory = Injekt.get(),
|
||||||
private val updateChapter: UpdateChapter = Injekt.get(),
|
private val updateChapter: UpdateChapter = Injekt.get(),
|
||||||
private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
|
private val setMangaViewerFlags: SetMangaViewerFlags = Injekt.get(),
|
||||||
@ -197,13 +187,8 @@ class ReaderViewModel(
|
|||||||
.map(::ReaderChapter)
|
.map(::ReaderChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var hasTrackers: Boolean = false
|
|
||||||
private val checkTrackers: (Manga) -> Unit = { manga ->
|
|
||||||
val tracks = runBlocking { getTracks.await(manga.id) }
|
|
||||||
hasTrackers = tracks.isNotEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val incognitoMode = preferences.incognitoMode().get()
|
private val incognitoMode = preferences.incognitoMode().get()
|
||||||
|
private val downloadAheadAmount = downloadPreferences.autoDownloadWhileReading().get()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// To save state
|
// To save state
|
||||||
@ -257,8 +242,6 @@ class ReaderViewModel(
|
|||||||
mutableState.update { it.copy(manga = manga) }
|
mutableState.update { it.copy(manga = manga) }
|
||||||
if (chapterId == -1L) chapterId = initialChapterId
|
if (chapterId == -1L) chapterId = initialChapterId
|
||||||
|
|
||||||
checkTrackers(manga)
|
|
||||||
|
|
||||||
val context = Injekt.get<Application>()
|
val context = Injekt.get<Application>()
|
||||||
val source = sourceManager.getOrStub(manga.source)
|
val source = sourceManager.getOrStub(manga.source)
|
||||||
loader = ChapterLoader(context, downloadManager, downloadProvider, manga, source)
|
loader = ChapterLoader(context, downloadManager, downloadProvider, manga, source)
|
||||||
@ -312,12 +295,15 @@ class ReaderViewModel(
|
|||||||
* Called when the user changed to the given [chapter] when changing pages from the viewer.
|
* Called when the user changed to the given [chapter] when changing pages from the viewer.
|
||||||
* It's used only to set this chapter as active.
|
* It's used only to set this chapter as active.
|
||||||
*/
|
*/
|
||||||
private suspend fun loadNewChapter(chapter: ReaderChapter) {
|
private fun loadNewChapter(chapter: ReaderChapter) {
|
||||||
val loader = loader ?: return
|
val loader = loader ?: return
|
||||||
|
|
||||||
logcat { "Loading ${chapter.chapter.url}" }
|
viewModelScope.launchIO {
|
||||||
|
logcat { "Loading ${chapter.chapter.url}" }
|
||||||
|
|
||||||
|
flushReadTimer()
|
||||||
|
restartReadTimer()
|
||||||
|
|
||||||
withIOContext {
|
|
||||||
try {
|
try {
|
||||||
loadChapter(loader, chapter)
|
loadChapter(loader, chapter)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
@ -356,7 +342,7 @@ class ReaderViewModel(
|
|||||||
* Called when the viewers decide it's a good time to preload a [chapter] and improve the UX so
|
* Called when the viewers decide it's a good time to preload a [chapter] and improve the UX so
|
||||||
* that the user doesn't have to wait too long to continue reading.
|
* that the user doesn't have to wait too long to continue reading.
|
||||||
*/
|
*/
|
||||||
private suspend fun preload(chapter: ReaderChapter) {
|
suspend fun preload(chapter: ReaderChapter) {
|
||||||
if (chapter.state is ReaderChapter.State.Loaded || chapter.state == ReaderChapter.State.Loading) {
|
if (chapter.state is ReaderChapter.State.Loaded || chapter.state == ReaderChapter.State.Loading) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -395,9 +381,7 @@ class ReaderViewModel(
|
|||||||
|
|
||||||
fun onViewerLoaded(viewer: Viewer?) {
|
fun onViewerLoaded(viewer: Viewer?) {
|
||||||
mutableState.update {
|
mutableState.update {
|
||||||
it.copy(
|
it.copy(viewer = viewer)
|
||||||
viewer = viewer,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,31 +396,19 @@ class ReaderViewModel(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentChapters = state.value.viewerChapters ?: return
|
|
||||||
val pages = page.chapter.pages ?: return
|
|
||||||
val selectedChapter = page.chapter
|
val selectedChapter = page.chapter
|
||||||
|
val pages = selectedChapter.pages ?: return
|
||||||
|
|
||||||
// Save last page read and mark as read if needed
|
// Save last page read and mark as read if needed
|
||||||
saveReadingProgress()
|
viewModelScope.launchNonCancellable {
|
||||||
mutableState.update {
|
updateChapterProgress(selectedChapter, page.index)
|
||||||
it.copy(
|
|
||||||
currentPage = page.index + 1,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (!incognitoMode) {
|
|
||||||
selectedChapter.chapter.last_page_read = page.index
|
|
||||||
if (selectedChapter.pages?.lastIndex == page.index) {
|
|
||||||
selectedChapter.chapter.read = true
|
|
||||||
updateTrackChapterRead(selectedChapter)
|
|
||||||
deleteChapterIfNeeded(selectedChapter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedChapter != currentChapters.currChapter) {
|
if (selectedChapter != getCurrentChapter()) {
|
||||||
logcat { "Setting ${selectedChapter.chapter.url} as active" }
|
logcat { "Setting ${selectedChapter.chapter.url} as active" }
|
||||||
setReadStartTime()
|
loadNewChapter(selectedChapter)
|
||||||
viewModelScope.launch { loadNewChapter(selectedChapter) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val inDownloadRange = page.number.toDouble() / pages.size > 0.25
|
val inDownloadRange = page.number.toDouble() / pages.size > 0.25
|
||||||
if (inDownloadRange) {
|
if (inDownloadRange) {
|
||||||
downloadNextChapters()
|
downloadNextChapters()
|
||||||
@ -444,12 +416,11 @@ class ReaderViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadNextChapters() {
|
private fun downloadNextChapters() {
|
||||||
|
if (downloadAheadAmount == 0) return
|
||||||
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
|
// Only download ahead if current + next chapter is already downloaded too to avoid jank
|
||||||
if (getCurrentChapter()?.pageLoader?.isLocal == true) return
|
if (getCurrentChapter()?.pageLoader !is DownloadPageLoader) return
|
||||||
val nextChapter = state.value.viewerChapters?.nextChapter?.chapter ?: return
|
val nextChapter = state.value.viewerChapters?.nextChapter?.chapter ?: return
|
||||||
|
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
@ -466,7 +437,7 @@ class ReaderViewModel(
|
|||||||
} else {
|
} else {
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
}.take(amount)
|
}.take(downloadAheadAmount)
|
||||||
|
|
||||||
downloadManager.downloadChapters(
|
downloadManager.downloadChapters(
|
||||||
manga,
|
manga,
|
||||||
@ -507,40 +478,51 @@ class ReaderViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when reader chapter is changed in reader or when activity is paused.
|
* Saves the chapter progress (last read page and whether it's read)
|
||||||
|
* if incognito mode isn't on.
|
||||||
*/
|
*/
|
||||||
private fun saveReadingProgress() {
|
private suspend fun updateChapterProgress(readerChapter: ReaderChapter, pageIndex: Int) {
|
||||||
|
mutableState.update {
|
||||||
|
it.copy(currentPage = pageIndex + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!incognitoMode) {
|
||||||
|
readerChapter.requestedPage = pageIndex
|
||||||
|
readerChapter.chapter.last_page_read = pageIndex
|
||||||
|
|
||||||
|
if (readerChapter.pages?.lastIndex == pageIndex) {
|
||||||
|
readerChapter.chapter.read = true
|
||||||
|
updateTrackChapterRead(readerChapter)
|
||||||
|
deleteChapterIfNeeded(readerChapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChapter.await(
|
||||||
|
ChapterUpdate(
|
||||||
|
id = readerChapter.chapter.id!!,
|
||||||
|
read = readerChapter.chapter.read,
|
||||||
|
bookmark = readerChapter.chapter.bookmark,
|
||||||
|
lastPageRead = readerChapter.chapter.last_page_read.toLong(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun restartReadTimer() {
|
||||||
|
chapterReadStartTime = Date().time
|
||||||
|
}
|
||||||
|
|
||||||
|
fun flushReadTimer() {
|
||||||
getCurrentChapter()?.let {
|
getCurrentChapter()?.let {
|
||||||
viewModelScope.launchNonCancellable {
|
viewModelScope.launchNonCancellable {
|
||||||
saveChapterProgress(it)
|
updateHistory(it)
|
||||||
saveChapterHistory(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves this [readerChapter] progress (last read page and whether it's read)
|
* Saves the chapter last read history if incognito mode isn't on.
|
||||||
* if incognito mode isn't on.
|
|
||||||
*/
|
*/
|
||||||
private suspend fun saveChapterProgress(readerChapter: ReaderChapter) {
|
private suspend fun updateHistory(readerChapter: ReaderChapter) {
|
||||||
if (incognitoMode) return
|
|
||||||
|
|
||||||
val chapter = readerChapter.chapter
|
|
||||||
readerChapter.requestedPage = chapter.last_page_read
|
|
||||||
updateChapter.await(
|
|
||||||
ChapterUpdate(
|
|
||||||
id = chapter.id!!,
|
|
||||||
read = chapter.read,
|
|
||||||
bookmark = chapter.bookmark,
|
|
||||||
lastPageRead = chapter.last_page_read.toLong(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves this [readerChapter] last read history if incognito mode isn't on.
|
|
||||||
*/
|
|
||||||
private suspend fun saveChapterHistory(readerChapter: ReaderChapter) {
|
|
||||||
if (incognitoMode) return
|
if (incognitoMode) return
|
||||||
|
|
||||||
val chapterId = readerChapter.chapter.id!!
|
val chapterId = readerChapter.chapter.id!!
|
||||||
@ -551,17 +533,6 @@ class ReaderViewModel(
|
|||||||
chapterReadStartTime = null
|
chapterReadStartTime = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setReadStartTime() {
|
|
||||||
chapterReadStartTime = Date().time
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called from the activity to preload the given [chapter].
|
|
||||||
*/
|
|
||||||
suspend fun preloadChapter(chapter: ReaderChapter) {
|
|
||||||
preload(chapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from the activity to load and set the next chapter as active.
|
* Called from the activity to load and set the next chapter as active.
|
||||||
*/
|
*/
|
||||||
@ -714,8 +685,8 @@ class ReaderViewModel(
|
|||||||
mutableState.update { it.copy(dialog = Dialog.PageActions(page)) }
|
mutableState.update { it.copy(dialog = Dialog.PageActions(page)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openColorFilterDialog() {
|
fun openSettingsDialog() {
|
||||||
mutableState.update { it.copy(dialog = Dialog.ColorFilter) }
|
mutableState.update { it.copy(dialog = Dialog.Settings) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeDialog() {
|
fun closeDialog() {
|
||||||
@ -839,44 +810,14 @@ class ReaderViewModel(
|
|||||||
* will run in a background thread and errors are ignored.
|
* will run in a background thread and errors are ignored.
|
||||||
*/
|
*/
|
||||||
private fun updateTrackChapterRead(readerChapter: ReaderChapter) {
|
private fun updateTrackChapterRead(readerChapter: ReaderChapter) {
|
||||||
if (incognitoMode || !hasTrackers) return
|
if (incognitoMode) return
|
||||||
if (!trackPreferences.autoUpdateTrack().get()) return
|
if (!trackPreferences.autoUpdateTrack().get()) return
|
||||||
|
|
||||||
val manga = manga ?: return
|
val manga = manga ?: return
|
||||||
val chapterRead = readerChapter.chapter.chapter_number.toDouble()
|
|
||||||
|
|
||||||
val trackManager = Injekt.get<TrackManager>()
|
|
||||||
val context = Injekt.get<Application>()
|
val context = Injekt.get<Application>()
|
||||||
|
|
||||||
viewModelScope.launchNonCancellable {
|
viewModelScope.launchNonCancellable {
|
||||||
getTracks.await(manga.id)
|
trackChapter.await(context, manga.id, readerChapter.chapter.chapter_number.toDouble())
|
||||||
.mapNotNull { track ->
|
|
||||||
val service = trackManager.getService(track.syncId)
|
|
||||||
if (service != null && service.isLogged && chapterRead > track.lastChapterRead) {
|
|
||||||
val updatedTrack = track.copy(lastChapterRead = chapterRead)
|
|
||||||
|
|
||||||
// We want these to execute even if the presenter is destroyed and leaks
|
|
||||||
// for a while. The view can still be garbage collected.
|
|
||||||
async {
|
|
||||||
runCatching {
|
|
||||||
try {
|
|
||||||
if (!context.isOnline()) error("Couldn't update tracker as device is offline")
|
|
||||||
service.update(updatedTrack.toDbTrack(), true)
|
|
||||||
insertTrack.await(updatedTrack)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
delayedTrackingStore.addItem(updatedTrack)
|
|
||||||
DelayedTrackingUpdateJob.setupTask(context)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.awaitAll()
|
|
||||||
.mapNotNull { it.exceptionOrNull() }
|
|
||||||
.forEach { logcat(LogPriority.INFO, it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -922,7 +863,7 @@ class ReaderViewModel(
|
|||||||
|
|
||||||
sealed class Dialog {
|
sealed class Dialog {
|
||||||
object Loading : Dialog()
|
object Loading : Dialog()
|
||||||
object ColorFilter : Dialog()
|
object Settings : Dialog()
|
||||||
data class PageActions(val page: ReaderPage) : Dialog()
|
data class PageActions(val page: ReaderPage) : Dialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.setting
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.platform.LocalView
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.window.DialogWindowProvider
|
|
||||||
import androidx.core.graphics.alpha
|
|
||||||
import androidx.core.graphics.blue
|
|
||||||
import androidx.core.graphics.green
|
|
||||||
import androidx.core.graphics.red
|
|
||||||
import eu.kanade.presentation.components.AdaptiveSheet
|
|
||||||
import eu.kanade.presentation.more.settings.LocalPreferenceMinHeight
|
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
|
||||||
import eu.kanade.presentation.more.settings.PreferenceScreen
|
|
||||||
import eu.kanade.presentation.util.collectAsState
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import tachiyomi.core.preference.getAndSet
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ReaderColorFilterDialog(
|
|
||||||
onDismissRequest: () -> Unit,
|
|
||||||
readerPreferences: ReaderPreferences,
|
|
||||||
) {
|
|
||||||
val colorFilterModes = buildList {
|
|
||||||
addAll(
|
|
||||||
listOf(
|
|
||||||
R.string.label_default,
|
|
||||||
R.string.filter_mode_multiply,
|
|
||||||
R.string.filter_mode_screen,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
||||||
addAll(
|
|
||||||
listOf(
|
|
||||||
R.string.filter_mode_overlay,
|
|
||||||
R.string.filter_mode_lighten,
|
|
||||||
R.string.filter_mode_darken,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}.map { stringResource(it) }
|
|
||||||
|
|
||||||
val customBrightness by readerPreferences.customBrightness().collectAsState()
|
|
||||||
val customBrightnessValue by readerPreferences.customBrightnessValue().collectAsState()
|
|
||||||
val colorFilter by readerPreferences.colorFilter().collectAsState()
|
|
||||||
val colorFilterValue by readerPreferences.colorFilterValue().collectAsState()
|
|
||||||
val colorFilterMode by readerPreferences.colorFilterMode().collectAsState()
|
|
||||||
|
|
||||||
AdaptiveSheet(
|
|
||||||
onDismissRequest = onDismissRequest,
|
|
||||||
) {
|
|
||||||
(LocalView.current.parent as? DialogWindowProvider)?.window?.setDimAmount(0f)
|
|
||||||
|
|
||||||
CompositionLocalProvider(
|
|
||||||
LocalPreferenceMinHeight provides 48.dp,
|
|
||||||
) {
|
|
||||||
PreferenceScreen(
|
|
||||||
items = listOfNotNull(
|
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
|
||||||
pref = readerPreferences.customBrightness(),
|
|
||||||
title = stringResource(R.string.pref_custom_brightness),
|
|
||||||
),
|
|
||||||
/**
|
|
||||||
* Sets the brightness of the screen. Range is [-75, 100].
|
|
||||||
* From -75 to -1 a semi-transparent black view is shown at the top with the minimum brightness.
|
|
||||||
* From 1 to 100 it sets that value as brightness.
|
|
||||||
* 0 sets system brightness and hides the overlay.
|
|
||||||
*/
|
|
||||||
Preference.PreferenceItem.SliderPreference(
|
|
||||||
value = customBrightnessValue,
|
|
||||||
title = stringResource(R.string.pref_custom_brightness),
|
|
||||||
min = -75,
|
|
||||||
max = 100,
|
|
||||||
onValueChanged = {
|
|
||||||
readerPreferences.customBrightnessValue().set(it)
|
|
||||||
true
|
|
||||||
},
|
|
||||||
).takeIf { customBrightness },
|
|
||||||
|
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
|
||||||
pref = readerPreferences.colorFilter(),
|
|
||||||
title = stringResource(R.string.pref_custom_color_filter),
|
|
||||||
),
|
|
||||||
Preference.PreferenceItem.SliderPreference(
|
|
||||||
value = colorFilterValue.red,
|
|
||||||
title = stringResource(R.string.color_filter_r_value),
|
|
||||||
max = 255,
|
|
||||||
onValueChanged = { newRValue ->
|
|
||||||
readerPreferences.colorFilterValue().getAndSet {
|
|
||||||
getColorValue(it, newRValue, RED_MASK, 16)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
).takeIf { colorFilter },
|
|
||||||
Preference.PreferenceItem.SliderPreference(
|
|
||||||
value = colorFilterValue.green,
|
|
||||||
title = stringResource(R.string.color_filter_g_value),
|
|
||||||
max = 255,
|
|
||||||
onValueChanged = { newRValue ->
|
|
||||||
readerPreferences.colorFilterValue().getAndSet {
|
|
||||||
getColorValue(it, newRValue, GREEN_MASK, 8)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
).takeIf { colorFilter },
|
|
||||||
Preference.PreferenceItem.SliderPreference(
|
|
||||||
value = colorFilterValue.blue,
|
|
||||||
title = stringResource(R.string.color_filter_b_value),
|
|
||||||
max = 255,
|
|
||||||
onValueChanged = { newRValue ->
|
|
||||||
readerPreferences.colorFilterValue().getAndSet {
|
|
||||||
getColorValue(it, newRValue, BLUE_MASK, 0)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
).takeIf { colorFilter },
|
|
||||||
Preference.PreferenceItem.SliderPreference(
|
|
||||||
value = colorFilterValue.alpha,
|
|
||||||
title = stringResource(R.string.color_filter_a_value),
|
|
||||||
max = 255,
|
|
||||||
onValueChanged = { newRValue ->
|
|
||||||
readerPreferences.colorFilterValue().getAndSet {
|
|
||||||
getColorValue(it, newRValue, ALPHA_MASK, 24)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
},
|
|
||||||
).takeIf { colorFilter },
|
|
||||||
Preference.PreferenceItem.BasicListPreference(
|
|
||||||
value = colorFilterMode.toString(),
|
|
||||||
title = stringResource(R.string.pref_color_filter_mode),
|
|
||||||
entries = colorFilterModes
|
|
||||||
.mapIndexed { index, mode -> index.toString() to mode }
|
|
||||||
.toMap(),
|
|
||||||
onValueChanged = { newValue ->
|
|
||||||
readerPreferences.colorFilterMode().set(newValue.toInt())
|
|
||||||
true
|
|
||||||
},
|
|
||||||
).takeIf { colorFilter },
|
|
||||||
|
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
|
||||||
pref = readerPreferences.grayscale(),
|
|
||||||
title = stringResource(R.string.pref_grayscale),
|
|
||||||
),
|
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
|
||||||
pref = readerPreferences.invertedColors(),
|
|
||||||
title = stringResource(R.string.pref_inverted_colors),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getColorValue(currentColor: Int, color: Int, mask: Long, bitShift: Int): Int {
|
|
||||||
return (color shl bitShift) or (currentColor and mask.inv().toInt())
|
|
||||||
}
|
|
||||||
private const val ALPHA_MASK: Long = 0xFF000000
|
|
||||||
private const val RED_MASK: Long = 0x00FF0000
|
|
||||||
private const val GREEN_MASK: Long = 0x0000FF00
|
|
||||||
private const val BLUE_MASK: Long = 0x000000FF
|
|
@ -1,53 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.setting
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.databinding.ReaderGeneralSettingsBinding
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
|
||||||
import eu.kanade.tachiyomi.util.preference.bindToPreference
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sheet to show reader and viewer preferences.
|
|
||||||
*/
|
|
||||||
class ReaderGeneralSettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
|
||||||
NestedScrollView(context, attrs) {
|
|
||||||
|
|
||||||
private val readerPreferences: ReaderPreferences by injectLazy()
|
|
||||||
|
|
||||||
private val binding = ReaderGeneralSettingsBinding.inflate(LayoutInflater.from(context), this, false)
|
|
||||||
|
|
||||||
init {
|
|
||||||
addView(binding.root)
|
|
||||||
|
|
||||||
initGeneralPreferences()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init general reader preferences.
|
|
||||||
*/
|
|
||||||
private fun initGeneralPreferences() {
|
|
||||||
binding.backgroundColor.bindToIntPreference(readerPreferences.readerTheme(), R.array.reader_themes_values)
|
|
||||||
binding.showPageNumber.bindToPreference(readerPreferences.showPageNumber())
|
|
||||||
binding.fullscreen.bindToPreference(readerPreferences.fullscreen())
|
|
||||||
readerPreferences.fullscreen().changes()
|
|
||||||
.onEach {
|
|
||||||
// If the preference is explicitly disabled, that means the setting was configured since there is a cutout
|
|
||||||
binding.cutoutShort.isVisible = it && ((context as ReaderActivity).hasCutout || !readerPreferences.cutoutShort().get())
|
|
||||||
binding.cutoutShort.bindToPreference(readerPreferences.cutoutShort())
|
|
||||||
}
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
|
|
||||||
binding.keepscreen.bindToPreference(readerPreferences.keepScreenOn())
|
|
||||||
binding.longTap.bindToPreference(readerPreferences.readWithLongTap())
|
|
||||||
binding.alwaysShowChapterTransition.bindToPreference(readerPreferences.alwaysShowChapterTransition())
|
|
||||||
binding.pageTransitions.bindToPreference(readerPreferences.pageTransitions())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.setting
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.widget.NestedScrollView
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import eu.kanade.domain.manga.model.orientationType
|
|
||||||
import eu.kanade.domain.manga.model.readingModeType
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.databinding.ReaderReadingModeSettingsBinding
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
|
||||||
import eu.kanade.tachiyomi.util.preference.bindToPreference
|
|
||||||
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sheet to show reader and viewer preferences.
|
|
||||||
*/
|
|
||||||
class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
|
|
||||||
NestedScrollView(context, attrs) {
|
|
||||||
|
|
||||||
private val readerPreferences: ReaderPreferences by injectLazy()
|
|
||||||
|
|
||||||
private val binding = ReaderReadingModeSettingsBinding.inflate(LayoutInflater.from(context), this, false)
|
|
||||||
|
|
||||||
init {
|
|
||||||
addView(binding.root)
|
|
||||||
|
|
||||||
initGeneralPreferences()
|
|
||||||
|
|
||||||
when ((context as ReaderActivity).viewModel.state.value.viewer) {
|
|
||||||
is PagerViewer -> initPagerPreferences()
|
|
||||||
is WebtoonViewer -> initWebtoonPreferences()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init general reader preferences.
|
|
||||||
*/
|
|
||||||
private fun initGeneralPreferences() {
|
|
||||||
binding.viewer.onItemSelectedListener = { position ->
|
|
||||||
val readingModeType = ReadingModeType.fromSpinner(position)
|
|
||||||
(context as ReaderActivity).viewModel.setMangaReadingMode(readingModeType.flagValue)
|
|
||||||
|
|
||||||
val mangaViewer = (context as ReaderActivity).viewModel.getMangaReadingMode()
|
|
||||||
if (mangaViewer == ReadingModeType.WEBTOON.flagValue || mangaViewer == ReadingModeType.CONTINUOUS_VERTICAL.flagValue) {
|
|
||||||
initWebtoonPreferences()
|
|
||||||
} else {
|
|
||||||
initPagerPreferences()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.viewer.setSelection((context as ReaderActivity).viewModel.manga?.readingModeType?.let { ReadingModeType.fromPreference(it.toInt()).prefValue } ?: ReadingModeType.DEFAULT.prefValue)
|
|
||||||
|
|
||||||
binding.rotationMode.onItemSelectedListener = { position ->
|
|
||||||
val rotationType = OrientationType.fromSpinner(position)
|
|
||||||
(context as ReaderActivity).viewModel.setMangaOrientationType(rotationType.flagValue)
|
|
||||||
}
|
|
||||||
binding.rotationMode.setSelection((context as ReaderActivity).viewModel.manga?.orientationType?.let { OrientationType.fromPreference(it.toInt()).prefValue } ?: OrientationType.DEFAULT.prefValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init the preferences for the pager reader.
|
|
||||||
*/
|
|
||||||
private fun initPagerPreferences() {
|
|
||||||
binding.webtoonPrefsGroup.root.isVisible = false
|
|
||||||
binding.pagerPrefsGroup.root.isVisible = true
|
|
||||||
|
|
||||||
binding.pagerPrefsGroup.tappingInverted.bindToPreference(readerPreferences.pagerNavInverted(), ReaderPreferences.TappingInvertMode::class.java)
|
|
||||||
binding.pagerPrefsGroup.navigatePan.bindToPreference(readerPreferences.navigateToPan())
|
|
||||||
|
|
||||||
binding.pagerPrefsGroup.pagerNav.bindToPreference(readerPreferences.navigationModePager())
|
|
||||||
readerPreferences.navigationModePager().changes()
|
|
||||||
.onEach {
|
|
||||||
val isTappingEnabled = it != 5
|
|
||||||
binding.pagerPrefsGroup.tappingInverted.isVisible = isTappingEnabled
|
|
||||||
binding.pagerPrefsGroup.navigatePan.isVisible = isTappingEnabled
|
|
||||||
}
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
// Makes so that landscape zoom gets hidden away when image scale type is not fit screen
|
|
||||||
binding.pagerPrefsGroup.scaleType.bindToPreference(readerPreferences.imageScaleType(), 1)
|
|
||||||
readerPreferences.imageScaleType().changes()
|
|
||||||
.onEach { binding.pagerPrefsGroup.landscapeZoom.isVisible = it == 1 }
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
binding.pagerPrefsGroup.landscapeZoom.bindToPreference(readerPreferences.landscapeZoom())
|
|
||||||
|
|
||||||
binding.pagerPrefsGroup.zoomStart.bindToPreference(readerPreferences.zoomStart(), 1)
|
|
||||||
binding.pagerPrefsGroup.cropBorders.bindToPreference(readerPreferences.cropBorders())
|
|
||||||
|
|
||||||
binding.pagerPrefsGroup.dualPageSplit.bindToPreference(readerPreferences.dualPageSplitPaged())
|
|
||||||
readerPreferences.dualPageSplitPaged().changes()
|
|
||||||
.onEach {
|
|
||||||
binding.pagerPrefsGroup.dualPageInvert.isVisible = it
|
|
||||||
if (it) {
|
|
||||||
binding.pagerPrefsGroup.dualPageRotateToFit.isChecked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
binding.pagerPrefsGroup.dualPageInvert.bindToPreference(readerPreferences.dualPageInvertPaged())
|
|
||||||
|
|
||||||
binding.pagerPrefsGroup.dualPageRotateToFit.bindToPreference(readerPreferences.dualPageRotateToFit())
|
|
||||||
readerPreferences.dualPageRotateToFit().changes()
|
|
||||||
.onEach {
|
|
||||||
binding.pagerPrefsGroup.dualPageRotateToFitInvert.isVisible = it
|
|
||||||
if (it) {
|
|
||||||
binding.pagerPrefsGroup.dualPageSplit.isChecked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
binding.pagerPrefsGroup.dualPageRotateToFitInvert.bindToPreference(readerPreferences.dualPageRotateToFitInvert())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init the preferences for the webtoon reader.
|
|
||||||
*/
|
|
||||||
private fun initWebtoonPreferences() {
|
|
||||||
binding.pagerPrefsGroup.root.isVisible = false
|
|
||||||
binding.webtoonPrefsGroup.root.isVisible = true
|
|
||||||
|
|
||||||
binding.webtoonPrefsGroup.tappingInverted.bindToPreference(readerPreferences.webtoonNavInverted(), ReaderPreferences.TappingInvertMode::class.java)
|
|
||||||
|
|
||||||
binding.webtoonPrefsGroup.webtoonNav.bindToPreference(readerPreferences.navigationModeWebtoon())
|
|
||||||
readerPreferences.navigationModeWebtoon().changes()
|
|
||||||
.onEach { binding.webtoonPrefsGroup.tappingInverted.isVisible = it != 5 }
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
binding.webtoonPrefsGroup.cropBordersWebtoon.bindToPreference(readerPreferences.cropBordersWebtoon())
|
|
||||||
binding.webtoonPrefsGroup.webtoonSidePadding.bindToIntPreference(readerPreferences.webtoonSidePadding(), R.array.webtoon_side_padding_values)
|
|
||||||
|
|
||||||
binding.webtoonPrefsGroup.dualPageSplit.bindToPreference(readerPreferences.dualPageSplitWebtoon())
|
|
||||||
// Makes it so that dual page invert gets hidden away when dual page split is turned off
|
|
||||||
readerPreferences.dualPageSplitWebtoon().changes()
|
|
||||||
.onEach { binding.webtoonPrefsGroup.dualPageInvert.isVisible = it }
|
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
|
||||||
binding.webtoonPrefsGroup.dualPageInvert.bindToPreference(readerPreferences.dualPageInvertWebtoon())
|
|
||||||
|
|
||||||
binding.webtoonPrefsGroup.longStripSplit.isVisible = !isReleaseBuildType
|
|
||||||
binding.webtoonPrefsGroup.longStripSplit.bindToPreference(readerPreferences.longStripSplitWebtoon())
|
|
||||||
|
|
||||||
binding.webtoonPrefsGroup.doubleTapZoom.bindToPreference(readerPreferences.webtoonDoubleTapZoomEnabled())
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,16 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.setting
|
||||||
|
|
||||||
|
import cafe.adriel.voyager.core.model.ScreenModel
|
||||||
|
import eu.kanade.tachiyomi.util.preference.toggle
|
||||||
|
import tachiyomi.core.preference.Preference
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class ReaderSettingsScreenModel(
|
||||||
|
val preferences: ReaderPreferences = Injekt.get(),
|
||||||
|
) : ScreenModel {
|
||||||
|
|
||||||
|
fun togglePreference(preference: (ReaderPreferences) -> Preference<Boolean>) {
|
||||||
|
preference(preferences).toggle()
|
||||||
|
}
|
||||||
|
}
|
@ -1,55 +1,136 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.setting
|
package eu.kanade.tachiyomi.ui.reader.setting
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import androidx.core.view.isVisible
|
||||||
import android.view.View
|
import androidx.lifecycle.lifecycleScope
|
||||||
import android.view.ViewGroup
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import eu.kanade.domain.manga.model.orientationType
|
||||||
|
import eu.kanade.domain.manga.model.readingModeType
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.databinding.CommonTabbedSheetBinding
|
import eu.kanade.tachiyomi.databinding.ReaderReadingModeSettingsBinding
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.widget.ViewPagerAdapter
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
|
||||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||||
|
import eu.kanade.tachiyomi.util.preference.bindToPreference
|
||||||
|
import eu.kanade.tachiyomi.util.system.isReleaseBuildType
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class ReaderSettingsSheet(
|
class ReaderSettingsSheet(
|
||||||
private val activity: ReaderActivity,
|
private val activity: ReaderActivity,
|
||||||
) : BaseBottomSheetDialog(activity) {
|
) : BottomSheetDialog(activity) {
|
||||||
|
|
||||||
private val tabs = listOf(
|
private val readerPreferences: ReaderPreferences by injectLazy()
|
||||||
ReaderReadingModeSettings(activity) to R.string.pref_category_reading_mode,
|
|
||||||
ReaderGeneralSettings(activity) to R.string.pref_category_general,
|
|
||||||
)
|
|
||||||
|
|
||||||
private lateinit var binding: CommonTabbedSheetBinding
|
private lateinit var binding: ReaderReadingModeSettingsBinding
|
||||||
|
|
||||||
override fun createView(inflater: LayoutInflater): View {
|
|
||||||
binding = CommonTabbedSheetBinding.inflate(activity.layoutInflater)
|
|
||||||
|
|
||||||
val adapter = Adapter()
|
|
||||||
binding.pager.adapter = adapter
|
|
||||||
binding.tabs.setupWithViewPager(binding.pager)
|
|
||||||
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
behavior.isFitToContents = false
|
binding = ReaderReadingModeSettingsBinding.inflate(activity.layoutInflater)
|
||||||
behavior.halfExpandedRatio = 0.25f
|
setContentView(binding.root)
|
||||||
|
|
||||||
|
initGeneralPreferences()
|
||||||
|
|
||||||
|
when (activity.viewModel.state.value.viewer) {
|
||||||
|
is PagerViewer -> initPagerPreferences()
|
||||||
|
is WebtoonViewer -> initWebtoonPreferences()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Adapter : ViewPagerAdapter() {
|
private fun initGeneralPreferences() {
|
||||||
|
binding.viewer.onItemSelectedListener = { position ->
|
||||||
|
val readingModeType = ReadingModeType.fromSpinner(position)
|
||||||
|
activity.viewModel.setMangaReadingMode(readingModeType.flagValue)
|
||||||
|
|
||||||
override fun createView(container: ViewGroup, position: Int): View {
|
val mangaViewer = activity.viewModel.getMangaReadingMode()
|
||||||
return tabs[position].first
|
if (mangaViewer == ReadingModeType.WEBTOON.flagValue || mangaViewer == ReadingModeType.CONTINUOUS_VERTICAL.flagValue) {
|
||||||
|
initWebtoonPreferences()
|
||||||
|
} else {
|
||||||
|
initPagerPreferences()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
binding.viewer.setSelection(activity.viewModel.manga?.readingModeType?.let { ReadingModeType.fromPreference(it.toInt()).prefValue } ?: ReadingModeType.DEFAULT.prefValue)
|
||||||
|
|
||||||
override fun getCount(): Int {
|
binding.rotationMode.onItemSelectedListener = { position ->
|
||||||
return tabs.size
|
val rotationType = OrientationType.fromSpinner(position)
|
||||||
|
activity.viewModel.setMangaOrientationType(rotationType.flagValue)
|
||||||
}
|
}
|
||||||
|
binding.rotationMode.setSelection(activity.viewModel.manga?.orientationType?.let { OrientationType.fromPreference(it.toInt()).prefValue } ?: OrientationType.DEFAULT.prefValue)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getPageTitle(position: Int): CharSequence {
|
private fun initPagerPreferences() {
|
||||||
return activity.resources!!.getString(tabs[position].second)
|
binding.webtoonPrefsGroup.root.isVisible = false
|
||||||
}
|
binding.pagerPrefsGroup.root.isVisible = true
|
||||||
|
|
||||||
|
binding.pagerPrefsGroup.tappingInverted.bindToPreference(readerPreferences.pagerNavInverted(), ReaderPreferences.TappingInvertMode::class.java)
|
||||||
|
binding.pagerPrefsGroup.navigatePan.bindToPreference(readerPreferences.navigateToPan())
|
||||||
|
|
||||||
|
binding.pagerPrefsGroup.pagerNav.bindToPreference(readerPreferences.navigationModePager())
|
||||||
|
readerPreferences.navigationModePager().changes()
|
||||||
|
.onEach {
|
||||||
|
val isTappingEnabled = it != 5
|
||||||
|
binding.pagerPrefsGroup.tappingInverted.isVisible = isTappingEnabled
|
||||||
|
binding.pagerPrefsGroup.navigatePan.isVisible = isTappingEnabled
|
||||||
|
}
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
// Makes so that landscape zoom gets hidden away when image scale type is not fit screen
|
||||||
|
binding.pagerPrefsGroup.scaleType.bindToPreference(readerPreferences.imageScaleType(), 1)
|
||||||
|
readerPreferences.imageScaleType().changes()
|
||||||
|
.onEach { binding.pagerPrefsGroup.landscapeZoom.isVisible = it == 1 }
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
binding.pagerPrefsGroup.landscapeZoom.bindToPreference(readerPreferences.landscapeZoom())
|
||||||
|
|
||||||
|
binding.pagerPrefsGroup.zoomStart.bindToPreference(readerPreferences.zoomStart(), 1)
|
||||||
|
binding.pagerPrefsGroup.cropBorders.bindToPreference(readerPreferences.cropBorders())
|
||||||
|
|
||||||
|
binding.pagerPrefsGroup.dualPageSplit.bindToPreference(readerPreferences.dualPageSplitPaged())
|
||||||
|
readerPreferences.dualPageSplitPaged().changes()
|
||||||
|
.onEach {
|
||||||
|
binding.pagerPrefsGroup.dualPageInvert.isVisible = it
|
||||||
|
if (it) {
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFit.isChecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
binding.pagerPrefsGroup.dualPageInvert.bindToPreference(readerPreferences.dualPageInvertPaged())
|
||||||
|
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFit.bindToPreference(readerPreferences.dualPageRotateToFit())
|
||||||
|
readerPreferences.dualPageRotateToFit().changes()
|
||||||
|
.onEach {
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFitInvert.isVisible = it
|
||||||
|
if (it) {
|
||||||
|
binding.pagerPrefsGroup.dualPageSplit.isChecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFitInvert.bindToPreference(readerPreferences.dualPageRotateToFitInvert())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initWebtoonPreferences() {
|
||||||
|
binding.pagerPrefsGroup.root.isVisible = false
|
||||||
|
binding.webtoonPrefsGroup.root.isVisible = true
|
||||||
|
|
||||||
|
binding.webtoonPrefsGroup.tappingInverted.bindToPreference(readerPreferences.webtoonNavInverted(), ReaderPreferences.TappingInvertMode::class.java)
|
||||||
|
|
||||||
|
binding.webtoonPrefsGroup.webtoonNav.bindToPreference(readerPreferences.navigationModeWebtoon())
|
||||||
|
readerPreferences.navigationModeWebtoon().changes()
|
||||||
|
.onEach { binding.webtoonPrefsGroup.tappingInverted.isVisible = it != 5 }
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
binding.webtoonPrefsGroup.cropBordersWebtoon.bindToPreference(readerPreferences.cropBordersWebtoon())
|
||||||
|
binding.webtoonPrefsGroup.webtoonSidePadding.bindToIntPreference(readerPreferences.webtoonSidePadding(), R.array.webtoon_side_padding_values)
|
||||||
|
|
||||||
|
binding.webtoonPrefsGroup.dualPageSplit.bindToPreference(readerPreferences.dualPageSplitWebtoon())
|
||||||
|
// Makes it so that dual page invert gets hidden away when dual page split is turned off
|
||||||
|
readerPreferences.dualPageSplitWebtoon().changes()
|
||||||
|
.onEach { binding.webtoonPrefsGroup.dualPageInvert.isVisible = it }
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
binding.webtoonPrefsGroup.dualPageInvert.bindToPreference(readerPreferences.dualPageInvertWebtoon())
|
||||||
|
|
||||||
|
binding.webtoonPrefsGroup.longStripSplit.isVisible = !isReleaseBuildType
|
||||||
|
binding.webtoonPrefsGroup.longStripSplit.bindToPreference(readerPreferences.longStripSplitWebtoon())
|
||||||
|
|
||||||
|
binding.webtoonPrefsGroup.doubleTapZoom.bindToPreference(readerPreferences.webtoonDoubleTapZoomEnabled())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,10 @@ import androidx.compose.ui.Modifier
|
|||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.Navigator
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.presentation.more.settings.screen.AboutScreen
|
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsAppearanceScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsBackupAndSyncScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsBackupAndSyncScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
import eu.kanade.presentation.more.settings.screen.SettingsMainScreen
|
||||||
|
import eu.kanade.presentation.more.settings.screen.about.AboutScreen
|
||||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
||||||
import eu.kanade.presentation.util.LocalBackPress
|
import eu.kanade.presentation.util.LocalBackPress
|
||||||
import eu.kanade.presentation.util.Screen
|
import eu.kanade.presentation.util.Screen
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.widget.sheet
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.DisplayMetrics
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.google.android.material.bottomsheet.getElevation
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.util.system.displayCompat
|
|
||||||
import eu.kanade.tachiyomi.util.system.isNightMode
|
|
||||||
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
|
|
||||||
|
|
||||||
abstract class BaseBottomSheetDialog(context: Context) : BottomSheetDialog(context) {
|
|
||||||
|
|
||||||
abstract fun createView(inflater: LayoutInflater): View
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
val rootView = createView(layoutInflater)
|
|
||||||
setContentView(rootView)
|
|
||||||
|
|
||||||
// Enforce max width for tablets
|
|
||||||
val width = context.resources.getDimensionPixelSize(R.dimen.bottom_sheet_width)
|
|
||||||
if (width > 0) {
|
|
||||||
behavior.maxWidth = width
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set peek height to 50% display height
|
|
||||||
context.displayCompat?.let {
|
|
||||||
val metrics = DisplayMetrics()
|
|
||||||
it.getRealMetrics(metrics)
|
|
||||||
behavior.peekHeight = metrics.heightPixels / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set navbar color to transparent for edge-to-edge bottom sheet if we can use light navigation bar
|
|
||||||
// TODO Replace deprecated systemUiVisibility when material-components uses new API to modify status bar icons
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
window?.setNavigationBarTransparentCompat(context, behavior.getElevation())
|
|
||||||
val bottomSheet = rootView.parent as ViewGroup
|
|
||||||
var flags = bottomSheet.systemUiVisibility
|
|
||||||
flags = if (context.isNightMode()) {
|
|
||||||
flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
|
|
||||||
} else {
|
|
||||||
flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
|
|
||||||
}
|
|
||||||
bottomSheet.systemUiVisibility = flags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.widget.sheet
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.View
|
|
||||||
import androidx.viewpager.widget.ViewPager
|
|
||||||
import java.lang.reflect.Field
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From https://github.com/kafumi/android-bottomsheet-viewpager
|
|
||||||
*/
|
|
||||||
class BottomSheetViewPager @JvmOverloads constructor(
|
|
||||||
context: Context,
|
|
||||||
attrs: AttributeSet? = null,
|
|
||||||
) : ViewPager(context, attrs) {
|
|
||||||
|
|
||||||
private val positionField: Field = LayoutParams::class.java.getDeclaredField("position").also {
|
|
||||||
it.isAccessible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChildAt(index: Int): View {
|
|
||||||
val currentView = getCurrentView() ?: return super.getChildAt(index)
|
|
||||||
return if (index == 0) {
|
|
||||||
currentView
|
|
||||||
} else {
|
|
||||||
var view = super.getChildAt(index)
|
|
||||||
if (view == currentView) {
|
|
||||||
view = super.getChildAt(0)
|
|
||||||
}
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getCurrentView(): View? {
|
|
||||||
for (i in 0 until childCount) {
|
|
||||||
val child = super.getChildAt(i)
|
|
||||||
val lp = child.layoutParams as? LayoutParams
|
|
||||||
if (lp != null) {
|
|
||||||
val position = positionField.getInt(lp)
|
|
||||||
if (!lp.isDecor && currentItem == position) {
|
|
||||||
return child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
addOnPageChangeListener(
|
|
||||||
object : SimpleOnPageChangeListener() {
|
|
||||||
override fun onPageSelected(position: Int) {
|
|
||||||
requestLayout()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="@android:color/black"
|
|
||||||
android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z" />
|
|
||||||
</vector>
|
|
@ -1,50 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/transparent_tabs_background">
|
|
||||||
|
|
||||||
<!-- Remove background color so rounded sheet corners work -->
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
|
||||||
android:id="@+id/tabs"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/menu"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:tabGravity="fill"
|
|
||||||
app:tabMode="fixed" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/menu"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/action_menu"
|
|
||||||
android:paddingStart="10dp"
|
|
||||||
android:paddingEnd="10dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_overflow_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.sheet.BottomSheetViewPager
|
|
||||||
android:id="@+id/pager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
@ -119,29 +119,29 @@
|
|||||||
app:tint="?attr/colorOnSurface" />
|
app:tint="?attr/colorOnSurface" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/action_settings_legacy"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/action_settings"
|
android:contentDescription="@string/action_settings"
|
||||||
android:padding="@dimen/screen_edge_margin"
|
android:padding="@dimen/screen_edge_margin"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/action_color_settings"
|
app:layout_constraintEnd_toStartOf="@+id/action_settings"
|
||||||
app:layout_constraintStart_toEndOf="@id/action_rotation"
|
app:layout_constraintStart_toEndOf="@id/action_rotation"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_settings_24dp"
|
app:srcCompat="@drawable/ic_settings_24dp"
|
||||||
app:tint="?attr/colorOnSurface" />
|
app:tint="?attr/colorOnSurface" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/action_color_settings"
|
android:id="@+id/action_settings"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/custom_filter"
|
android:contentDescription="@string/action_settings"
|
||||||
android:padding="@dimen/screen_edge_margin"
|
android:padding="@dimen/screen_edge_margin"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/action_settings"
|
app:layout_constraintStart_toEndOf="@id/action_settings_legacy"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_brightness_5_24dp"
|
app:srcCompat="@drawable/ic_settings_24dp"
|
||||||
app:tint="?attr/colorOnSurface" />
|
app:tint="?attr/colorOnSurface" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
|
||||||
android:id="@+id/background_color"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:entries="@array/reader_themes"
|
|
||||||
app:title="@string/pref_reader_theme" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/show_page_number"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_show_page_number"
|
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/fullscreen"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_fullscreen"
|
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/cutout_short"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_cutout_short"
|
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/keepscreen"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_keep_screen_on"
|
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/long_tap"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_read_with_long_tap"
|
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/always_show_chapter_transition"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_always_show_chapter_transition"
|
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/page_transitions"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:paddingVertical="16dp"
|
|
||||||
android:text="@string/pref_page_transitions"
|
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
@ -1,5 +1,3 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<dimen name="bottom_sheet_width">480dp</dimen>
|
|
||||||
|
|
||||||
<dimen name="screen_edge_margin">24dp</dimen>
|
<dimen name="screen_edge_margin">24dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -9,20 +9,6 @@
|
|||||||
<item>@string/vertical_plus_viewer</item>
|
<item>@string/vertical_plus_viewer</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="reader_themes">
|
|
||||||
<item>@string/black_background</item>
|
|
||||||
<item>@string/gray_background</item>
|
|
||||||
<item>@string/white_background</item>
|
|
||||||
<item>@string/automatic_background</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string-array name="reader_themes_values">
|
|
||||||
<item>1</item>
|
|
||||||
<item>2</item>
|
|
||||||
<item>0</item>
|
|
||||||
<item>3</item>
|
|
||||||
</string-array>
|
|
||||||
|
|
||||||
<string-array name="image_scale_type">
|
<string-array name="image_scale_type">
|
||||||
<item>@string/scale_type_fit_screen</item>
|
<item>@string/scale_type_fit_screen</item>
|
||||||
<item>@string/scale_type_stretch</item>
|
<item>@string/scale_type_stretch</item>
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<dimen name="bottom_sheet_width">0dp</dimen>
|
|
||||||
|
|
||||||
<dimen name="dialog_radius">8dp</dimen>
|
<dimen name="dialog_radius">8dp</dimen>
|
||||||
|
|
||||||
<dimen name="screen_edge_margin">16dp</dimen>
|
<dimen name="screen_edge_margin">16dp</dimen>
|
||||||
|
16
core/src/main/java/tachiyomi/core/preference/TriState.kt
Normal file
16
core/src/main/java/tachiyomi/core/preference/TriState.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package tachiyomi.core.preference
|
||||||
|
|
||||||
|
enum class TriState {
|
||||||
|
DISABLED, // Disable filter
|
||||||
|
ENABLED_IS, // Enabled with "is" filter
|
||||||
|
ENABLED_NOT, // Enabled with "not" filter
|
||||||
|
;
|
||||||
|
|
||||||
|
fun next(): TriState {
|
||||||
|
return when (this) {
|
||||||
|
DISABLED -> ENABLED_IS
|
||||||
|
ENABLED_IS -> ENABLED_NOT
|
||||||
|
ENABLED_NOT -> DISABLED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@ package tachiyomi.data.chapter
|
|||||||
|
|
||||||
import tachiyomi.domain.chapter.model.Chapter
|
import tachiyomi.domain.chapter.model.Chapter
|
||||||
|
|
||||||
val chapterMapper: (Long, Long, String, String, String?, Boolean, Boolean, Long, Float, Long, Long, Long, Long?) -> Chapter =
|
val chapterMapper: (Long, Long, String, String, String?, Boolean, Boolean, Long, Float, Long, Long, Long, Long) -> Chapter =
|
||||||
{ id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt ->
|
{ id, mangaId, url, name, scanlator, read, bookmark, lastPageRead, chapterNumber, sourceOrder, dateFetch, dateUpload, lastModifiedAt ->
|
||||||
Chapter(
|
Chapter(
|
||||||
id = id,
|
id = id,
|
||||||
|
@ -4,8 +4,8 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
|||||||
import tachiyomi.domain.library.model.LibraryManga
|
import tachiyomi.domain.library.model.LibraryManga
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
|
||||||
val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long?) -> Manga =
|
val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?) -> Manga =
|
||||||
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt ->
|
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt ->
|
||||||
Manga(
|
Manga(
|
||||||
id = id,
|
id = id,
|
||||||
source = source,
|
source = source,
|
||||||
@ -28,11 +28,12 @@ val mangaMapper: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||||||
updateStrategy = updateStrategy,
|
updateStrategy = updateStrategy,
|
||||||
initialized = initialized,
|
initialized = initialized,
|
||||||
lastModifiedAt = lastModifiedAt,
|
lastModifiedAt = lastModifiedAt,
|
||||||
|
favoriteModifiedAt = favoriteModifiedAt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long?, Long, Long, Long, Long, Long, Long, Long) -> LibraryManga =
|
val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?, String, Long, String?, Boolean, Long?, Long?, Boolean, Long, Long, Long, Long, UpdateStrategy, Long, Long, Long?, Long, Long, Long, Long, Long, Long, Long) -> LibraryManga =
|
||||||
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category ->
|
{ id, source, url, artist, author, description, genre, title, status, thumbnailUrl, favorite, lastUpdate, nextUpdate, initialized, viewerFlags, chapterFlags, coverLastModified, dateAdded, updateStrategy, calculateInterval, lastModifiedAt, favoriteModifiedAt, totalCount, readCount, latestUpload, chapterFetchedAt, lastRead, bookmarkCount, category ->
|
||||||
LibraryManga(
|
LibraryManga(
|
||||||
manga = mangaMapper(
|
manga = mangaMapper(
|
||||||
id,
|
id,
|
||||||
@ -56,6 +57,7 @@ val libraryManga: (Long, Long, String, String?, String?, String?, List<String>?,
|
|||||||
updateStrategy,
|
updateStrategy,
|
||||||
calculateInterval,
|
calculateInterval,
|
||||||
lastModifiedAt,
|
lastModifiedAt,
|
||||||
|
favoriteModifiedAt,
|
||||||
),
|
),
|
||||||
category = category,
|
category = category,
|
||||||
totalChapters = totalCount,
|
totalChapters = totalCount,
|
||||||
|
@ -11,7 +11,7 @@ CREATE TABLE chapters(
|
|||||||
source_order INTEGER NOT NULL,
|
source_order INTEGER NOT NULL,
|
||||||
date_fetch INTEGER AS Long NOT NULL,
|
date_fetch INTEGER AS Long NOT NULL,
|
||||||
date_upload INTEGER AS Long NOT NULL,
|
date_upload INTEGER AS Long NOT NULL,
|
||||||
last_modified_at INTEGER AS Long,
|
last_modified_at INTEGER AS Long NOT NULL,
|
||||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
@ -60,8 +60,8 @@ DELETE FROM chapters
|
|||||||
WHERE _id IN :chapterIds;
|
WHERE _id IN :chapterIds;
|
||||||
|
|
||||||
insert:
|
insert:
|
||||||
INSERT INTO chapters(manga_id,url,name,scanlator,read,bookmark,last_page_read,chapter_number,source_order,date_fetch,date_upload)
|
INSERT INTO chapters(manga_id, url, name, scanlator, read, bookmark, last_page_read, chapter_number, source_order, date_fetch, date_upload, last_modified_at)
|
||||||
VALUES (:mangaId,:url,:name,:scanlator,:read,:bookmark,:lastPageRead,:chapterNumber,:sourceOrder,:dateFetch,:dateUpload);
|
VALUES (:mangaId, :url, :name, :scanlator, :read, :bookmark, :lastPageRead, :chapterNumber, :sourceOrder, :dateFetch, :dateUpload, strftime('%s', 'now'));
|
||||||
|
|
||||||
update:
|
update:
|
||||||
UPDATE chapters
|
UPDATE chapters
|
||||||
|
@ -23,23 +23,23 @@ CREATE TABLE mangas(
|
|||||||
date_added INTEGER AS Long NOT NULL,
|
date_added INTEGER AS Long NOT NULL,
|
||||||
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
|
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
|
||||||
calculate_interval INTEGER DEFAULT 0 NOT NULL,
|
calculate_interval INTEGER DEFAULT 0 NOT NULL,
|
||||||
last_modified_at INTEGER AS Long
|
last_modified_at INTEGER AS Long NOT NULL,
|
||||||
|
favorite_modified_at INTEGER AS Long
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;
|
CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;
|
||||||
CREATE INDEX mangas_url_index ON mangas(url);
|
CREATE INDEX mangas_url_index ON mangas(url);
|
||||||
|
|
||||||
CREATE TRIGGER update_last_modified_at_mangas
|
CREATE TRIGGER update_favorite_modified_at_mangas
|
||||||
AFTER UPDATE ON mangas
|
AFTER UPDATE OF favorite ON mangas
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE mangas
|
UPDATE mangas
|
||||||
SET last_modified_at = strftime('%s', 'now')
|
SET favorite_modified_at = strftime('%s', 'now')
|
||||||
WHERE _id = new._id;
|
WHERE _id = new._id;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER insert_last_modified_at_mangas
|
CREATE TRIGGER update_last_modified_at_mangas
|
||||||
AFTER INSERT ON mangas
|
AFTER UPDATE ON mangas
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE mangas
|
UPDATE mangas
|
||||||
@ -68,6 +68,11 @@ getAllManga:
|
|||||||
SELECT *
|
SELECT *
|
||||||
FROM mangas;
|
FROM mangas;
|
||||||
|
|
||||||
|
getMangasWithFavoriteTimestamp:
|
||||||
|
SELECT *
|
||||||
|
FROM mangas
|
||||||
|
WHERE favorite_modified_at IS NOT NULL;
|
||||||
|
|
||||||
getSourceIdWithFavoriteCount:
|
getSourceIdWithFavoriteCount:
|
||||||
SELECT
|
SELECT
|
||||||
source,
|
source,
|
||||||
@ -104,8 +109,8 @@ DELETE FROM mangas
|
|||||||
WHERE favorite = 0 AND source IN :sourceIds;
|
WHERE favorite = 0 AND source IN :sourceIds;
|
||||||
|
|
||||||
insert:
|
insert:
|
||||||
INSERT INTO mangas(source,url,artist,author,description,genre,title,status,thumbnail_url,favorite,last_update,next_update,initialized,viewer,chapter_flags,cover_last_modified,date_added,update_strategy,calculate_interval)
|
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at)
|
||||||
VALUES (:source,:url,:artist,:author,:description,:genre,:title,:status,:thumbnailUrl,:favorite,:lastUpdate,:nextUpdate,:initialized,:viewerFlags,:chapterFlags,:coverLastModified,:dateAdded,:updateStrategy,:calculateInterval);
|
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, strftime('%s', 'now'));
|
||||||
|
|
||||||
update:
|
update:
|
||||||
UPDATE mangas SET
|
UPDATE mangas SET
|
||||||
|
@ -2,7 +2,7 @@ CREATE TABLE mangas_categories(
|
|||||||
_id INTEGER NOT NULL PRIMARY KEY,
|
_id INTEGER NOT NULL PRIMARY KEY,
|
||||||
manga_id INTEGER NOT NULL,
|
manga_id INTEGER NOT NULL,
|
||||||
category_id INTEGER NOT NULL,
|
category_id INTEGER NOT NULL,
|
||||||
last_modified_at INTEGER AS Long,
|
last_modified_at INTEGER AS Long NOT NULL,
|
||||||
FOREIGN KEY(category_id) REFERENCES categories (_id)
|
FOREIGN KEY(category_id) REFERENCES categories (_id)
|
||||||
ON DELETE CASCADE,
|
ON DELETE CASCADE,
|
||||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
||||||
@ -18,18 +18,9 @@ BEGIN
|
|||||||
WHERE _id = new._id;
|
WHERE _id = new._id;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
CREATE TRIGGER insert_last_modified_at_mangas_categories
|
|
||||||
AFTER INSERT ON mangas_categories
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
UPDATE mangas_categories
|
|
||||||
SET last_modified_at = strftime('%s', 'now')
|
|
||||||
WHERE _id = new._id;
|
|
||||||
END;
|
|
||||||
|
|
||||||
insert:
|
insert:
|
||||||
INSERT INTO mangas_categories(manga_id, category_id)
|
INSERT INTO mangas_categories(manga_id, category_id, last_modified_at)
|
||||||
VALUES (:mangaId, :categoryId);
|
VALUES (:mangaId, :categoryId, strftime('%s', 'now'));
|
||||||
|
|
||||||
deleteMangaCategoryByMangaId:
|
deleteMangaCategoryByMangaId:
|
||||||
DELETE FROM mangas_categories
|
DELETE FROM mangas_categories
|
||||||
|
@ -1,94 +1,12 @@
|
|||||||
import kotlin.collections.List;
|
ALTER TABLE mangas ADD COLUMN last_modified_at INTEGER AS Long NOT NULL DEFAULT 0;
|
||||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy;
|
ALTER TABLE mangas ADD COLUMN favorite_modified_at INTEGER AS Long;
|
||||||
|
ALTER TABLE mangas_categories ADD COLUMN last_modified_at INTEGER AS Long NOT NULL DEFAULT 0;
|
||||||
-- Drop indices
|
ALTER TABLE chapters ADD COLUMN last_modified_at INTEGER AS Long NOT NULL DEFAULT 0;
|
||||||
DROP INDEX IF EXISTS library_favorite_index;
|
|
||||||
DROP INDEX IF EXISTS mangas_url_index;
|
|
||||||
DROP INDEX IF EXISTS chapters_manga_id_index;
|
|
||||||
DROP INDEX IF EXISTS chapters_unread_by_manga_index;
|
|
||||||
|
|
||||||
-- Rename existing tables to temporary tables
|
|
||||||
ALTER TABLE mangas RENAME TO mangas_temp;
|
|
||||||
ALTER TABLE chapters RENAME TO chapters_temp;
|
|
||||||
ALTER TABLE mangas_categories RENAME TO mangas_categories_temp;
|
|
||||||
|
|
||||||
-- Create new tables with updated schema
|
|
||||||
CREATE TABLE mangas(
|
|
||||||
_id INTEGER NOT NULL PRIMARY KEY,
|
|
||||||
source INTEGER NOT NULL,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
artist TEXT,
|
|
||||||
author TEXT,
|
|
||||||
description TEXT,
|
|
||||||
genre TEXT AS List<String>,
|
|
||||||
title TEXT NOT NULL,
|
|
||||||
status INTEGER NOT NULL,
|
|
||||||
thumbnail_url TEXT,
|
|
||||||
favorite INTEGER AS Boolean NOT NULL,
|
|
||||||
last_update INTEGER AS Long,
|
|
||||||
next_update INTEGER AS Long,
|
|
||||||
initialized INTEGER AS Boolean NOT NULL,
|
|
||||||
viewer INTEGER NOT NULL,
|
|
||||||
chapter_flags INTEGER NOT NULL,
|
|
||||||
cover_last_modified INTEGER AS Long NOT NULL,
|
|
||||||
date_added INTEGER AS Long NOT NULL,
|
|
||||||
update_strategy INTEGER AS UpdateStrategy NOT NULL DEFAULT 0,
|
|
||||||
last_modified_at INTEGER AS Long
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE mangas_categories(
|
|
||||||
_id INTEGER NOT NULL PRIMARY KEY,
|
|
||||||
manga_id INTEGER NOT NULL,
|
|
||||||
category_id INTEGER NOT NULL,
|
|
||||||
last_modified_at INTEGER AS Long,
|
|
||||||
FOREIGN KEY(category_id) REFERENCES categories (_id)
|
|
||||||
ON DELETE CASCADE,
|
|
||||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE chapters(
|
|
||||||
_id INTEGER NOT NULL PRIMARY KEY,
|
|
||||||
manga_id INTEGER NOT NULL,
|
|
||||||
url TEXT NOT NULL,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
scanlator TEXT,
|
|
||||||
read INTEGER AS Boolean NOT NULL,
|
|
||||||
bookmark INTEGER AS Boolean NOT NULL,
|
|
||||||
last_page_read INTEGER NOT NULL,
|
|
||||||
chapter_number REAL AS Float NOT NULL,
|
|
||||||
source_order INTEGER NOT NULL,
|
|
||||||
date_fetch INTEGER AS Long NOT NULL,
|
|
||||||
date_upload INTEGER AS Long NOT NULL,
|
|
||||||
last_modified_at INTEGER AS Long,
|
|
||||||
FOREIGN KEY(manga_id) REFERENCES mangas (_id)
|
|
||||||
ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Copy data from temporary tables to new tables
|
|
||||||
INSERT INTO mangas
|
|
||||||
SELECT _id, source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, NULL
|
|
||||||
FROM mangas_temp;
|
|
||||||
|
|
||||||
INSERT INTO chapters
|
|
||||||
SELECT _id, manga_id, url, name, scanlator, read, bookmark, last_page_read, chapter_number, source_order, date_fetch, date_upload, NULL
|
|
||||||
FROM chapters_temp;
|
|
||||||
|
|
||||||
INSERT INTO mangas_categories
|
|
||||||
SELECT _id, manga_id, category_id, NULL
|
|
||||||
FROM mangas_categories_temp;
|
|
||||||
|
|
||||||
-- Create indices
|
|
||||||
CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;
|
|
||||||
CREATE INDEX mangas_url_index ON mangas(url);
|
|
||||||
CREATE INDEX chapters_manga_id_index ON chapters(manga_id);
|
|
||||||
CREATE INDEX chapters_unread_by_manga_index ON chapters(manga_id, read) WHERE read = 0;
|
|
||||||
|
|
||||||
-- Drop temporary tables
|
|
||||||
DROP TABLE IF EXISTS mangas_temp;
|
|
||||||
DROP TABLE IF EXISTS chapters_temp;
|
|
||||||
DROP TABLE IF EXISTS mangas_categories_temp;
|
|
||||||
|
|
||||||
|
UPDATE mangas SET last_modified_at = strftime('%s', 'now');
|
||||||
|
UPDATE mangas SET favorite_modified_at = strftime('%s', 'now') WHERE favorite = 1;
|
||||||
|
UPDATE mangas_categories SET last_modified_at = strftime('%s', 'now');
|
||||||
|
UPDATE chapters SET last_modified_at = strftime('%s', 'now');
|
||||||
|
|
||||||
-- Create triggers
|
-- Create triggers
|
||||||
DROP TRIGGER IF EXISTS update_last_modified_at_mangas;
|
DROP TRIGGER IF EXISTS update_last_modified_at_mangas;
|
||||||
@ -101,13 +19,12 @@ BEGIN
|
|||||||
WHERE _id = new._id;
|
WHERE _id = new._id;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS insert_last_modified_at_mangas;
|
DROP TRIGGER IF EXISTS update_favorite_modified_at_mangas;
|
||||||
CREATE TRIGGER insert_last_modified_at_mangas
|
CREATE TRIGGER update_last_favorited_at_mangas
|
||||||
AFTER INSERT ON mangas
|
AFTER UPDATE OF favorite ON mangas
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
BEGIN
|
||||||
UPDATE mangas
|
UPDATE mangas
|
||||||
SET last_modified_at = strftime('%s', 'now')
|
SET favorite_modified_at = strftime('%s', 'now')
|
||||||
WHERE _id = new._id;
|
WHERE _id = new._id;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
@ -130,13 +47,3 @@ BEGIN
|
|||||||
SET last_modified_at = strftime('%s', 'now')
|
SET last_modified_at = strftime('%s', 'now')
|
||||||
WHERE _id = new._id;
|
WHERE _id = new._id;
|
||||||
END;
|
END;
|
||||||
|
|
||||||
DROP TRIGGER IF EXISTS insert_last_modified_at_mangas_categories;
|
|
||||||
CREATE TRIGGER insert_last_modified_at_mangas_categories
|
|
||||||
AFTER INSERT ON mangas_categories
|
|
||||||
FOR EACH ROW
|
|
||||||
BEGIN
|
|
||||||
UPDATE mangas_categories
|
|
||||||
SET last_modified_at = strftime('%s', 'now')
|
|
||||||
WHERE _id = new._id;
|
|
||||||
END;
|
|
||||||
|
@ -13,7 +13,7 @@ data class Chapter(
|
|||||||
val dateUpload: Long,
|
val dateUpload: Long,
|
||||||
val chapterNumber: Float,
|
val chapterNumber: Float,
|
||||||
val scanlator: String?,
|
val scanlator: String?,
|
||||||
val lastModifiedAt: Long?,
|
val lastModifiedAt: Long,
|
||||||
) {
|
) {
|
||||||
val isRecognizedNumber: Boolean
|
val isRecognizedNumber: Boolean
|
||||||
get() = chapterNumber >= 0f
|
get() = chapterNumber >= 0f
|
||||||
@ -32,7 +32,7 @@ data class Chapter(
|
|||||||
dateUpload = -1,
|
dateUpload = -1,
|
||||||
chapterNumber = -1f,
|
chapterNumber = -1f,
|
||||||
scanlator = null,
|
scanlator = null,
|
||||||
lastModifiedAt = null,
|
lastModifiedAt = 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package tachiyomi.domain.library.service
|
package tachiyomi.domain.library.service
|
||||||
|
|
||||||
import tachiyomi.core.preference.PreferenceStore
|
import tachiyomi.core.preference.PreferenceStore
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import tachiyomi.core.preference.getEnum
|
import tachiyomi.core.preference.getEnum
|
||||||
import tachiyomi.domain.library.model.LibraryDisplayMode
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
||||||
import tachiyomi.domain.library.model.LibrarySort
|
import tachiyomi.domain.library.model.LibrarySort
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import tachiyomi.domain.manga.model.TriStateFilter
|
|
||||||
|
|
||||||
class LibraryPreferences(
|
class LibraryPreferences(
|
||||||
private val preferenceStore: PreferenceStore,
|
private val preferenceStore: PreferenceStore,
|
||||||
@ -49,27 +49,27 @@ class LibraryPreferences(
|
|||||||
|
|
||||||
// region Filter
|
// region Filter
|
||||||
|
|
||||||
fun filterDownloaded() = preferenceStore.getEnum("pref_filter_library_downloaded_v2", TriStateFilter.DISABLED)
|
fun filterDownloaded() = preferenceStore.getEnum("pref_filter_library_downloaded_v2", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterUnread() = preferenceStore.getEnum("pref_filter_library_unread_v2", TriStateFilter.DISABLED)
|
fun filterUnread() = preferenceStore.getEnum("pref_filter_library_unread_v2", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterStarted() = preferenceStore.getEnum("pref_filter_library_started_v2", TriStateFilter.DISABLED)
|
fun filterStarted() = preferenceStore.getEnum("pref_filter_library_started_v2", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterBookmarked() = preferenceStore.getEnum("pref_filter_library_bookmarked_v2", TriStateFilter.DISABLED)
|
fun filterBookmarked() = preferenceStore.getEnum("pref_filter_library_bookmarked_v2", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterCompleted() = preferenceStore.getEnum("pref_filter_library_completed_v2", TriStateFilter.DISABLED)
|
fun filterCompleted() = preferenceStore.getEnum("pref_filter_library_completed_v2", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterIntervalCustom() = preferenceStore.getEnum("pref_filter_library_interval_custom", TriStateFilter.DISABLED)
|
fun filterIntervalCustom() = preferenceStore.getEnum("pref_filter_library_interval_custom", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterIntervalLong() = preferenceStore.getEnum("pref_filter_library_interval_long", TriStateFilter.DISABLED)
|
fun filterIntervalLong() = preferenceStore.getEnum("pref_filter_library_interval_long", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterIntervalLate() = preferenceStore.getEnum("pref_filter_library_interval_late", TriStateFilter.DISABLED)
|
fun filterIntervalLate() = preferenceStore.getEnum("pref_filter_library_interval_late", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterIntervalDropped() = preferenceStore.getEnum("pref_filter_library_interval_dropped", TriStateFilter.DISABLED)
|
fun filterIntervalDropped() = preferenceStore.getEnum("pref_filter_library_interval_dropped", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterIntervalPassed() = preferenceStore.getEnum("pref_filter_library_interval_passed", TriStateFilter.DISABLED)
|
fun filterIntervalPassed() = preferenceStore.getEnum("pref_filter_library_interval_passed", TriState.DISABLED)
|
||||||
|
|
||||||
fun filterTracking(id: Int) = preferenceStore.getEnum("pref_filter_library_tracked_${id}_v2", TriStateFilter.DISABLED)
|
fun filterTracking(id: Int) = preferenceStore.getEnum("pref_filter_library_tracked_${id}_v2", TriState.DISABLED)
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
@ -134,9 +134,9 @@ class LibraryPreferences(
|
|||||||
|
|
||||||
// region Swipe Actions
|
// region Swipe Actions
|
||||||
|
|
||||||
fun swipeEndAction() = preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleBookmark)
|
fun swipeToStartAction() = preferenceStore.getEnum("pref_chapter_swipe_end_action", ChapterSwipeAction.ToggleBookmark)
|
||||||
|
|
||||||
fun swipeStartAction() = preferenceStore.getEnum("pref_chapter_swipe_start_action", ChapterSwipeAction.ToggleRead)
|
fun swipeToEndAction() = preferenceStore.getEnum("pref_chapter_swipe_start_action", ChapterSwipeAction.ToggleRead)
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package tachiyomi.domain.manga.model
|
package tachiyomi.domain.manga.model
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Manga(
|
data class Manga(
|
||||||
@ -24,7 +25,8 @@ data class Manga(
|
|||||||
val thumbnailUrl: String?,
|
val thumbnailUrl: String?,
|
||||||
val updateStrategy: UpdateStrategy,
|
val updateStrategy: UpdateStrategy,
|
||||||
val initialized: Boolean,
|
val initialized: Boolean,
|
||||||
val lastModifiedAt: Long?,
|
val lastModifiedAt: Long,
|
||||||
|
val favoriteModifiedAt: Long?,
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
|
|
||||||
val sorting: Long
|
val sorting: Long
|
||||||
@ -42,18 +44,18 @@ data class Manga(
|
|||||||
val bookmarkedFilterRaw: Long
|
val bookmarkedFilterRaw: Long
|
||||||
get() = chapterFlags and CHAPTER_BOOKMARKED_MASK
|
get() = chapterFlags and CHAPTER_BOOKMARKED_MASK
|
||||||
|
|
||||||
val unreadFilter: TriStateFilter
|
val unreadFilter: TriState
|
||||||
get() = when (unreadFilterRaw) {
|
get() = when (unreadFilterRaw) {
|
||||||
CHAPTER_SHOW_UNREAD -> TriStateFilter.ENABLED_IS
|
CHAPTER_SHOW_UNREAD -> TriState.ENABLED_IS
|
||||||
CHAPTER_SHOW_READ -> TriStateFilter.ENABLED_NOT
|
CHAPTER_SHOW_READ -> TriState.ENABLED_NOT
|
||||||
else -> TriStateFilter.DISABLED
|
else -> TriState.DISABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
val bookmarkedFilter: TriStateFilter
|
val bookmarkedFilter: TriState
|
||||||
get() = when (bookmarkedFilterRaw) {
|
get() = when (bookmarkedFilterRaw) {
|
||||||
CHAPTER_SHOW_BOOKMARKED -> TriStateFilter.ENABLED_IS
|
CHAPTER_SHOW_BOOKMARKED -> TriState.ENABLED_IS
|
||||||
CHAPTER_SHOW_NOT_BOOKMARKED -> TriStateFilter.ENABLED_NOT
|
CHAPTER_SHOW_NOT_BOOKMARKED -> TriState.ENABLED_NOT
|
||||||
else -> TriStateFilter.DISABLED
|
else -> TriState.DISABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sortDescending(): Boolean {
|
fun sortDescending(): Boolean {
|
||||||
@ -111,6 +113,7 @@ data class Manga(
|
|||||||
updateStrategy = UpdateStrategy.ALWAYS_UPDATE,
|
updateStrategy = UpdateStrategy.ALWAYS_UPDATE,
|
||||||
initialized = false,
|
initialized = false,
|
||||||
lastModifiedAt = 0L,
|
lastModifiedAt = 0L,
|
||||||
|
favoriteModifiedAt = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package tachiyomi.domain.manga.model
|
||||||
|
|
||||||
|
import tachiyomi.core.preference.TriState
|
||||||
|
|
||||||
|
inline fun applyFilter(filter: TriState, predicate: () -> Boolean): Boolean = when (filter) {
|
||||||
|
TriState.DISABLED -> true
|
||||||
|
TriState.ENABLED_IS -> predicate()
|
||||||
|
TriState.ENABLED_NOT -> !predicate()
|
||||||
|
}
|
@ -1,22 +0,0 @@
|
|||||||
package tachiyomi.domain.manga.model
|
|
||||||
|
|
||||||
enum class TriStateFilter {
|
|
||||||
DISABLED, // Disable filter
|
|
||||||
ENABLED_IS, // Enabled with "is" filter
|
|
||||||
ENABLED_NOT, // Enabled with "not" filter
|
|
||||||
;
|
|
||||||
|
|
||||||
fun next(): TriStateFilter {
|
|
||||||
return when (this) {
|
|
||||||
DISABLED -> ENABLED_IS
|
|
||||||
ENABLED_IS -> ENABLED_NOT
|
|
||||||
ENABLED_NOT -> DISABLED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun applyFilter(filter: TriStateFilter, predicate: () -> Boolean): Boolean = when (filter) {
|
|
||||||
TriStateFilter.DISABLED -> true
|
|
||||||
TriStateFilter.ENABLED_IS -> predicate()
|
|
||||||
TriStateFilter.ENABLED_NOT -> !predicate()
|
|
||||||
}
|
|
@ -1,7 +1,7 @@
|
|||||||
[versions]
|
[versions]
|
||||||
compiler = "1.4.8"
|
compiler = "1.4.8"
|
||||||
compose-bom = "2023.06.00-alpha01"
|
compose-bom = "2023.07.00-alpha01"
|
||||||
accompanist = "0.31.4-beta"
|
accompanist = "0.31.5-beta"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
activity = "androidx.activity:activity-compose:1.7.2"
|
activity = "androidx.activity:activity-compose:1.7.2"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
aboutlib_version = "10.8.0"
|
aboutlib_version = "10.8.2"
|
||||||
okhttp_version = "5.0.0-alpha.11"
|
okhttp_version = "5.0.0-alpha.11"
|
||||||
shizuku_version = "12.2.0"
|
shizuku_version = "12.2.0"
|
||||||
sqlite = "2.3.1"
|
sqlite = "2.3.1"
|
||||||
@ -20,7 +20,7 @@ flowreactivenetwork = "ru.beryukhov:flowreactivenetwork:1.0.4"
|
|||||||
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp_version" }
|
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp_version" }
|
||||||
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp_version" }
|
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp_version" }
|
||||||
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" }
|
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp_version" }
|
||||||
okio = "com.squareup.okio:okio:3.3.0"
|
okio = "com.squareup.okio:okio:3.4.0"
|
||||||
|
|
||||||
conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2"
|
conscrypt-android = "org.conscrypt:conscrypt-android:2.5.2"
|
||||||
|
|
||||||
@ -58,9 +58,11 @@ flexible-adapter-core = "com.github.arkon.FlexibleAdapter:flexible-adapter:c8013
|
|||||||
photoview = "com.github.chrisbanes:PhotoView:2.3.0"
|
photoview = "com.github.chrisbanes:PhotoView:2.3.0"
|
||||||
directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0"
|
directionalviewpager = "com.github.tachiyomiorg:DirectionalViewPager:1.0.0"
|
||||||
insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
|
insetter = "dev.chrisbanes.insetter:insetter:0.6.1"
|
||||||
compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.3"
|
compose-materialmotion = "io.github.fornewid:material-motion-compose-core:1.0.4"
|
||||||
compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0"
|
compose-simpleicons = "br.com.devsrsouza.compose.icons.android:simple-icons:1.0.0"
|
||||||
|
|
||||||
|
swipe = "me.saket.swipe:swipe:1.2.0"
|
||||||
|
|
||||||
logcat = "com.squareup.logcat:logcat:0.1"
|
logcat = "com.squareup.logcat:logcat:0.1"
|
||||||
|
|
||||||
acra-http = "ch.acra:acra-http:5.10.1"
|
acra-http = "ch.acra:acra-http:5.10.1"
|
||||||
|
@ -831,4 +831,5 @@
|
|||||||
<string name="skipped_reason_not_in_release_period">S’ha omès perquè no se n’espera cap publicació avui</string>
|
<string name="skipped_reason_not_in_release_period">S’ha omès perquè no se n’espera cap publicació avui</string>
|
||||||
<string name="action_filter_interval_passed">Període de comprovació superat</string>
|
<string name="action_filter_interval_passed">Període de comprovació superat</string>
|
||||||
<string name="pref_update_release_grace_period_info">Es recomana un període de gràcia baix per a minimitzar la sobrecàrrega de les fonts. Com més comprovacions fallides es produeixin, més interval hi haurà entre comprovacions, fins a un màxim de 28 dies.</string>
|
<string name="pref_update_release_grace_period_info">Es recomana un període de gràcia baix per a minimitzar la sobrecàrrega de les fonts. Com més comprovacions fallides es produeixin, més interval hi haurà entre comprovacions, fins a un màxim de 28 dies.</string>
|
||||||
|
<string name="delete_downloaded">Suprimeix els baixats</string>
|
||||||
</resources>
|
</resources>
|
@ -639,7 +639,7 @@
|
|||||||
<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 mezipaměť kapitol při zavření aplikace</string>
|
<string name="pref_auto_clear_chapter_cache">Vymazat mezipaměť kapitol při spuštění 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>
|
||||||
@ -849,4 +849,5 @@
|
|||||||
<string name="track_delete_remote_text">Odebrat také z %s</string>
|
<string name="track_delete_remote_text">Odebrat také z %s</string>
|
||||||
<string name="action_ok">OK</string>
|
<string name="action_ok">OK</string>
|
||||||
<string name="track_delete_title">Odebrat sledování %s\?</string>
|
<string name="track_delete_title">Odebrat sledování %s\?</string>
|
||||||
|
<string name="delete_downloaded">Odstranit stažené</string>
|
||||||
</resources>
|
</resources>
|
@ -565,7 +565,7 @@
|
|||||||
<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="pref_reader_summary">Вулав тытӑмӗ, кӑтартӑнни, куҫӑм</string>
|
<string name="pref_reader_summary">Вулав тытӑмӗ, кӑтартӑнни, куҫӑм</string>
|
||||||
<string name="label_default">Пӳрӳлле</string>
|
<string name="label_default">Йаланхилле</string>
|
||||||
<string name="action_open_random_manga">Ӑнсӑрт ҫырав уҫ</string>
|
<string name="action_open_random_manga">Ӑнсӑрт ҫырав уҫ</string>
|
||||||
<string name="theme_strawberrydaiquiri">Ҫӗр ҫырли тайккирийӗ</string>
|
<string name="theme_strawberrydaiquiri">Ҫӗр ҫырли тайккирийӗ</string>
|
||||||
<string name="theme_midnightdusk">Ҫур ҫӗр ӗнтрӗкӗ</string>
|
<string name="theme_midnightdusk">Ҫур ҫӗр ӗнтрӗкӗ</string>
|
||||||
@ -630,4 +630,5 @@
|
|||||||
<string name="ext_info_version">Версси</string>
|
<string name="ext_info_version">Версси</string>
|
||||||
<string name="pref_library_update_refresh_trackers">Йӗрлеве хӑй-хальлӗн ҫӗнетни</string>
|
<string name="pref_library_update_refresh_trackers">Йӗрлеве хӑй-хальлӗн ҫӗнетни</string>
|
||||||
<string name="ext_update_all">Пурне те ҫӗнет</string>
|
<string name="ext_update_all">Пурне те ҫӗнет</string>
|
||||||
|
<string name="delete_downloaded">Тийесе илнисене катерт</string>
|
||||||
</resources>
|
</resources>
|
@ -386,7 +386,7 @@
|
|||||||
<string name="add_to_library">Zur Bibliothek hinzufügen</string>
|
<string name="add_to_library">Zur Bibliothek hinzufügen</string>
|
||||||
<string name="confirm_exit">Zum Beenden nochmal die Zurück-Taste drücken</string>
|
<string name="confirm_exit">Zum Beenden nochmal die Zurück-Taste drücken</string>
|
||||||
<string name="information_webview_required">WebView ist für Tachiyomi erforderlich</string>
|
<string name="information_webview_required">WebView ist für Tachiyomi erforderlich</string>
|
||||||
<string name="licenses">Quelloffene Lizenzen</string>
|
<string name="licenses">Open-Source-Lizenzen</string>
|
||||||
<string name="website">Webseite</string>
|
<string name="website">Webseite</string>
|
||||||
<string name="label_downloaded_only">Nur Heruntergeladenes</string>
|
<string name="label_downloaded_only">Nur Heruntergeladenes</string>
|
||||||
<string name="recent_manga_time">Kap. %1$s - %2$s</string>
|
<string name="recent_manga_time">Kap. %1$s - %2$s</string>
|
||||||
@ -628,7 +628,7 @@
|
|||||||
<string name="download_queue_size_warning">Achtung: Große Downloads könnten dazu führen, dass Quellen langsamer werden und/oder Tachiyomi blockieren. Tippe, um mehr zu erfahren.</string>
|
<string name="download_queue_size_warning">Achtung: Große Downloads könnten dazu führen, dass Quellen langsamer werden und/oder Tachiyomi blockieren. Tippe, um mehr zu erfahren.</string>
|
||||||
<string name="ext_update_all">Alle aktualisieren</string>
|
<string name="ext_update_all">Alle aktualisieren</string>
|
||||||
<string name="channel_app_updates">Anwendungsaktualisierungen</string>
|
<string name="channel_app_updates">Anwendungsaktualisierungen</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Kapitel-Zwischenspeicher beim Schließen der App löschen</string>
|
<string name="pref_auto_clear_chapter_cache">Kapitel-Zwischenspeicher beim Öffnen der App löschen</string>
|
||||||
<string name="clear_database_source_item_count">%1$d Nicht-Bibliothekseinträge in der Datenbank</string>
|
<string name="clear_database_source_item_count">%1$d Nicht-Bibliothekseinträge in der Datenbank</string>
|
||||||
<string name="database_clean">Nichts zu bereinigen</string>
|
<string name="database_clean">Nichts zu bereinigen</string>
|
||||||
<string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string>
|
<string name="extension_api_error">Herunterladen der Erweiterungsliste ist fehlgeschlagen</string>
|
||||||
@ -831,4 +831,5 @@
|
|||||||
<string name="track_delete_remote_text">Auch aus %s entfernen</string>
|
<string name="track_delete_remote_text">Auch aus %s entfernen</string>
|
||||||
<string name="action_ok">OK</string>
|
<string name="action_ok">OK</string>
|
||||||
<string name="track_delete_title">Tracking von %s entfernen\?</string>
|
<string name="track_delete_title">Tracking von %s entfernen\?</string>
|
||||||
|
<string name="delete_downloaded">Heruntergeladenes löschen</string>
|
||||||
</resources>
|
</resources>
|
@ -628,7 +628,7 @@
|
|||||||
<string name="download_queue_size_warning">Προειδοποίηση: οι μαζικές λήψεις ενδέχεται να οδηγήσουν σε επιβράδυνση των πηγών ή/και αποκλεισμό του Tachiyomi. Πατήστε για να μάθετε περισσότερα.</string>
|
<string name="download_queue_size_warning">Προειδοποίηση: οι μαζικές λήψεις ενδέχεται να οδηγήσουν σε επιβράδυνση των πηγών ή/και αποκλεισμό του Tachiyomi. Πατήστε για να μάθετε περισσότερα.</string>
|
||||||
<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 καταχωρήσεις εκτός βιβλιοθήκης στη βάση δεδομένων</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>
|
||||||
@ -831,4 +831,5 @@
|
|||||||
<string name="track_delete_title">Κατάργηση παρακολούθησης %s;</string>
|
<string name="track_delete_title">Κατάργηση παρακολούθησης %s;</string>
|
||||||
<string name="track_delete_remote_text">Επίσης, αφαιρέστε από %s</string>
|
<string name="track_delete_remote_text">Επίσης, αφαιρέστε από %s</string>
|
||||||
<string name="track_delete_text">Αυτό θα καταργήσει την παρακολούθηση τοπικά.</string>
|
<string name="track_delete_text">Αυτό θα καταργήσει την παρακολούθηση τοπικά.</string>
|
||||||
|
<string name="delete_downloaded">Διαγραφή ληφθέντων</string>
|
||||||
</resources>
|
</resources>
|
@ -671,7 +671,7 @@
|
|||||||
<string name="download_queue_size_warning">Advertencia: Las descargas grandes pueden llevar a que las fuentes se vuelvan cada vez más lentas y en casos extremos que los servidores limiten o impidan el acceso a Tachiyomi. Toca aquí para más información.</string>
|
<string name="download_queue_size_warning">Advertencia: Las descargas grandes pueden llevar a que las fuentes se vuelvan cada vez más lentas y en casos extremos que los servidores limiten o impidan el acceso a Tachiyomi. Toca aquí para más información.</string>
|
||||||
<string name="ext_update_all">Actualizar todas</string>
|
<string name="ext_update_all">Actualizar todas</string>
|
||||||
<string name="channel_app_updates">Actualizaciones de la aplicación</string>
|
<string name="channel_app_updates">Actualizaciones de la aplicación</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Borrar la caché de capítulos al cerrar la aplicación</string>
|
<string name="pref_auto_clear_chapter_cache">Borrar la caché de capítulos al abrir la aplicación</string>
|
||||||
<string name="database_clean">Base de datos limpia</string>
|
<string name="database_clean">Base de datos limpia</string>
|
||||||
<string name="clear_database_source_item_count">Hay %1$d elementos en la base de datos que no están en la biblioteca</string>
|
<string name="clear_database_source_item_count">Hay %1$d elementos en la base de datos que no están en la biblioteca</string>
|
||||||
<string name="extension_api_error">No se pudo descargar el listado de extensiones</string>
|
<string name="extension_api_error">No se pudo descargar el listado de extensiones</string>
|
||||||
@ -880,4 +880,5 @@
|
|||||||
<string name="track_delete_title">¿Quitar el rastreo de %s\?</string>
|
<string name="track_delete_title">¿Quitar el rastreo de %s\?</string>
|
||||||
<string name="track_delete_text">Esto eliminará el seguimiento localmente.</string>
|
<string name="track_delete_text">Esto eliminará el seguimiento localmente.</string>
|
||||||
<string name="track_delete_remote_text">Quitar también de %s</string>
|
<string name="track_delete_remote_text">Quitar también de %s</string>
|
||||||
|
<string name="delete_downloaded">Borrar los ya descargados</string>
|
||||||
</resources>
|
</resources>
|
@ -64,7 +64,7 @@
|
|||||||
<string name="action_sort_total">Dami ng kabanata</string>
|
<string name="action_sort_total">Dami ng kabanata</string>
|
||||||
<string name="action_sort_alpha">Pa-alpabeto</string>
|
<string name="action_sort_alpha">Pa-alpabeto</string>
|
||||||
<string name="action_filter_empty">Tanggalin ang pansala</string>
|
<string name="action_filter_empty">Tanggalin ang pansala</string>
|
||||||
<string name="action_filter_unread">Babasahin</string>
|
<string name="action_filter_unread">Hindi Nabasa</string>
|
||||||
<string name="action_filter_bookmarked">Tinandaan</string>
|
<string name="action_filter_bookmarked">Tinandaan</string>
|
||||||
<string name="action_filter">Pansala</string>
|
<string name="action_filter">Pansala</string>
|
||||||
<string name="action_menu">Menu</string>
|
<string name="action_menu">Menu</string>
|
||||||
@ -801,10 +801,10 @@
|
|||||||
<string name="pref_chapter_swipe_end">Mag-swipe ng pakanang pagkilos</string>
|
<string name="pref_chapter_swipe_end">Mag-swipe ng pakanang pagkilos</string>
|
||||||
<string name="action_set_interval">Itakda ang pagitan</string>
|
<string name="action_set_interval">Itakda ang pagitan</string>
|
||||||
<string name="action_filter_interval_custom">Sinadyang takdang pagkuha</string>
|
<string name="action_filter_interval_custom">Sinadyang takdang pagkuha</string>
|
||||||
<string name="action_filter_interval_late">Nahuling 10+ pagsusuri</string>
|
<string name="action_filter_interval_late">Huling 10+ pagsusuri</string>
|
||||||
<string name="action_sort_next_updated">Susunod na inaasahang update</string>
|
<string name="action_sort_next_updated">Susunod na inaasahang update</string>
|
||||||
<string name="action_filter_interval_dropped">Nawala\? or Nahulog\? (depending on the context, \"Nahulog\" means dropped or dropped something, and \"Nawala\" means Gone/Vanished) Nahuling 20+ at 2 buwan</string>
|
<string name="action_filter_interval_dropped">Nawala\? or Nahulog\? (depending on the context, \"Nahulog\" means dropped or dropped something, and \"Nawala\" means Gone/Vanished) Nahuling 20+ at 2 buwan</string>
|
||||||
<string name="action_filter_interval_passed">Lumipas ang check period</string>
|
<string name="action_filter_interval_passed">Lumipas na panahon ng pagsuri</string>
|
||||||
<string name="action_filter_interval_long">Kunin kada buwan (kada ika-28 na araw)</string>
|
<string name="action_filter_interval_long">Kunin kada buwan (kada ika-28 na araw)</string>
|
||||||
<plurals name="pref_update_release_following_days">
|
<plurals name="pref_update_release_following_days">
|
||||||
<item quantity="one">pagkatapos ng %d araw</item>
|
<item quantity="one">pagkatapos ng %d araw</item>
|
||||||
|
@ -314,7 +314,7 @@
|
|||||||
<string name="theme_system">सिस्टम का पालन करें</string>
|
<string name="theme_system">सिस्टम का पालन करें</string>
|
||||||
<string name="pref_manage_notifications">सूचनाओं का प्रबंधन</string>
|
<string name="pref_manage_notifications">सूचनाओं का प्रबंधन</string>
|
||||||
<string name="pref_category_security">सुरक्षा और गोपनीयता</string>
|
<string name="pref_category_security">सुरक्षा और गोपनीयता</string>
|
||||||
<string name="lock_with_biometrics">अनलॉक की आवश्यकता है</string>
|
<string name="lock_with_biometrics">खोलने की आवश्यकता है</string>
|
||||||
<string name="lock_when_idle">निष्क्रिय होने पर लॉक करें</string>
|
<string name="lock_when_idle">निष्क्रिय होने पर लॉक करें</string>
|
||||||
<string name="lock_always">हमेशा</string>
|
<string name="lock_always">हमेशा</string>
|
||||||
<string name="lock_never">कभी नहीँ</string>
|
<string name="lock_never">कभी नहीँ</string>
|
||||||
@ -739,4 +739,9 @@
|
|||||||
<string name="pref_page_rotate">फिट होने के लिए चौड़े पृष्ठों को घुमाएं</string>
|
<string name="pref_page_rotate">फिट होने के लिए चौड़े पृष्ठों को घुमाएं</string>
|
||||||
<string name="pref_backup_summary">मैनुअल और स्वचालित बैकअप</string>
|
<string name="pref_backup_summary">मैनुअल और स्वचालित बैकअप</string>
|
||||||
<string name="pref_security_summary">ऐप लॉक, सुरक्षित स्क्रीन</string>
|
<string name="pref_security_summary">ऐप लॉक, सुरक्षित स्क्रीन</string>
|
||||||
|
<string name="action_set_interval">अंतराल निर्धारित करें</string>
|
||||||
|
<string name="action_filter_interval_custom">अनुकूलित लाने का अंतराल</string>
|
||||||
|
<string name="action_filter_interval_long">मासिक प्राप्त करें (28 दिन)</string>
|
||||||
|
<string name="action_filter_interval_late">देर से 10+ की जाँच</string>
|
||||||
|
<string name="action_filter_interval_dropped">छोड़ा हुआ\? देर से 20+ और 2 महीने</string>
|
||||||
</resources>
|
</resources>
|
@ -673,7 +673,7 @@
|
|||||||
<string name="download_queue_size_warning">Attenzione: grossi download di massa possono rallentare le fonti e/o bloccare tachiyomi. Tocca per saperne di più.</string>
|
<string name="download_queue_size_warning">Attenzione: grossi download di massa possono rallentare le fonti e/o bloccare tachiyomi. Tocca per saperne di più.</string>
|
||||||
<string name="ext_update_all">Aggiorna tutto</string>
|
<string name="ext_update_all">Aggiorna tutto</string>
|
||||||
<string name="channel_app_updates">Aggiornamenti dell\'applicazione</string>
|
<string name="channel_app_updates">Aggiornamenti dell\'applicazione</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Cancella la cache capitoli alla chiusura dell\'app</string>
|
<string name="pref_auto_clear_chapter_cache">Cancella la cache capitoli all\'avvio dell\'app</string>
|
||||||
<string name="clear_database_source_item_count">%1$d voci non presenti in libreria nel database</string>
|
<string name="clear_database_source_item_count">%1$d voci non presenti in libreria nel database</string>
|
||||||
<string name="database_clean">Niente da Pulire</string>
|
<string name="database_clean">Niente da Pulire</string>
|
||||||
<string name="extension_api_error">Impossibile ottenere l\'elenco estensioni</string>
|
<string name="extension_api_error">Impossibile ottenere l\'elenco estensioni</string>
|
||||||
@ -882,4 +882,5 @@
|
|||||||
<string name="track_delete_remote_text">Rimuovi anche da %s</string>
|
<string name="track_delete_remote_text">Rimuovi anche da %s</string>
|
||||||
<string name="action_ok">OK</string>
|
<string name="action_ok">OK</string>
|
||||||
<string name="track_delete_text">Questo rimuoverà il tracciamento locale.</string>
|
<string name="track_delete_text">Questo rimuoverà il tracciamento locale.</string>
|
||||||
|
<string name="delete_downloaded">Cancella scaricati</string>
|
||||||
</resources>
|
</resources>
|
@ -616,7 +616,7 @@
|
|||||||
<string name="download_queue_size_warning">Amaran: muat turun secara pukal besar boleh menyebabkan sumber menjadi lebih perlahan dan/atau menyekat Tachiyomi. Ketik untuk ketahui selebihnya.</string>
|
<string name="download_queue_size_warning">Amaran: muat turun secara pukal besar boleh menyebabkan sumber menjadi lebih perlahan dan/atau menyekat Tachiyomi. Ketik untuk ketahui selebihnya.</string>
|
||||||
<string name="ext_update_all">Kemas kini semua</string>
|
<string name="ext_update_all">Kemas kini semua</string>
|
||||||
<string name="channel_app_updates">Kemas kini aplikasi</string>
|
<string name="channel_app_updates">Kemas kini aplikasi</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Hapus cache bab apabila menutup aplikasi</string>
|
<string name="pref_auto_clear_chapter_cache">Hapus cache bab apabila membuka aplikasi</string>
|
||||||
<string name="database_clean">Tiada apa untuk dibersihkan</string>
|
<string name="database_clean">Tiada apa untuk dibersihkan</string>
|
||||||
<string name="clear_database_source_item_count">%1$d entri bukan pustaka dalam pangkalan data</string>
|
<string name="clear_database_source_item_count">%1$d entri bukan pustaka dalam pangkalan data</string>
|
||||||
<string name="extension_api_error">Gagal mendapatkan senarai sambungan</string>
|
<string name="extension_api_error">Gagal mendapatkan senarai sambungan</string>
|
||||||
@ -813,4 +813,5 @@
|
|||||||
<string name="track_delete_text">Ini akan membuang penjejakan secara lokal.</string>
|
<string name="track_delete_text">Ini akan membuang penjejakan secara lokal.</string>
|
||||||
<string name="action_ok">OK</string>
|
<string name="action_ok">OK</string>
|
||||||
<string name="track_delete_remote_text">Juga buang daripada %s</string>
|
<string name="track_delete_remote_text">Juga buang daripada %s</string>
|
||||||
|
<string name="delete_downloaded">Padam dimuat turun</string>
|
||||||
</resources>
|
</resources>
|
@ -421,7 +421,7 @@
|
|||||||
<string name="notification_chapters_single">अध्याय %1$s</string>
|
<string name="notification_chapters_single">अध्याय %1$s</string>
|
||||||
<string name="scale_type_original_size">मूल आकार</string>
|
<string name="scale_type_original_size">मूल आकार</string>
|
||||||
<string name="pref_zoom_start">जूम सुरु स्थिति</string>
|
<string name="pref_zoom_start">जूम सुरु स्थिति</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">एप बन्दमा अध्याय क्यास खाली गर्नुहोस्</string>
|
<string name="pref_auto_clear_chapter_cache">एप खोलेमा अध्याय क्यास खाली गर्नुहोस्</string>
|
||||||
<string name="information_webview_outdated">राम्रो संगतताको लागि कृपया WebView एप अपडेट गर्नुहोस्</string>
|
<string name="information_webview_outdated">राम्रो संगतताको लागि कृपया WebView एप अपडेट गर्नुहोस्</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>
|
||||||
@ -696,7 +696,7 @@
|
|||||||
<string name="confirm_add_duplicate_manga">तपाईको पुस्तकालयमा एउटै नामको इन्ट्री छ।
|
<string name="confirm_add_duplicate_manga">तपाईको पुस्तकालयमा एउटै नामको इन्ट्री छ।
|
||||||
\n
|
\n
|
||||||
\nके तपाईं अझै जारी राख्न चाहनुहुन्छ\?</string>
|
\nके तपाईं अझै जारी राख्न चाहनुहुन्छ\?</string>
|
||||||
<string name="reading_list">पढ्ने सूची</string>
|
<string name="reading_list">पढिरहेको सूची</string>
|
||||||
<string name="updates_last_update_info">पुस्तकालय पछिल्लो पटक अपडेट गरिएको: %s</string>
|
<string name="updates_last_update_info">पुस्तकालय पछिल्लो पटक अपडेट गरिएको: %s</string>
|
||||||
<string name="crash_screen_description">%s एक अप्रत्याशित त्रुटिमा पर्यो। समर्थन को लागि हामी तपाईंलाई हाम्रो Discord को #support च्यानलमा क्र्यास लगहरू साझेदारी गर्न सुझाव दिन्छौं।</string>
|
<string name="crash_screen_description">%s एक अप्रत्याशित त्रुटिमा पर्यो। समर्थन को लागि हामी तपाईंलाई हाम्रो Discord को #support च्यानलमा क्र्यास लगहरू साझेदारी गर्न सुझाव दिन्छौं।</string>
|
||||||
<string name="update_check_open">GitHub मा खोल्नुहोस्</string>
|
<string name="update_check_open">GitHub मा खोल्नुहोस्</string>
|
||||||
@ -831,4 +831,5 @@
|
|||||||
<string name="track_delete_remote_text">%s बाट पनि हटाउनुहोस्</string>
|
<string name="track_delete_remote_text">%s बाट पनि हटाउनुहोस्</string>
|
||||||
<string name="track_delete_text">यसले लोकल रूपमा ट्र्याकिङ हटाउनेछ।</string>
|
<string name="track_delete_text">यसले लोकल रूपमा ट्र्याकिङ हटाउनेछ।</string>
|
||||||
<string name="action_ok">ठीक छ</string>
|
<string name="action_ok">ठीक छ</string>
|
||||||
|
<string name="delete_downloaded">डाउनलोड गरिएको मेट्नुहोस्</string>
|
||||||
</resources>
|
</resources>
|
@ -640,7 +640,7 @@
|
|||||||
<string name="download_queue_size_warning">Aviso: grandes downloads em massa podem levar as fontes a ficarem lentas e/ou começarem a bloquear o Tachiyomi. Toque para saber mais.</string>
|
<string name="download_queue_size_warning">Aviso: grandes downloads em massa podem levar as fontes a ficarem lentas e/ou começarem a bloquear o Tachiyomi. Toque para saber mais.</string>
|
||||||
<string name="ext_update_all">Atualizar tudo</string>
|
<string name="ext_update_all">Atualizar tudo</string>
|
||||||
<string name="channel_app_updates">Atualizações do aplicativo</string>
|
<string name="channel_app_updates">Atualizações do aplicativo</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Limpar o cache de capítulos ao fechar o aplicativo</string>
|
<string name="pref_auto_clear_chapter_cache">Limpar o cache de capítulos ao abrir o aplicativo</string>
|
||||||
<string name="clear_database_source_item_count">%1$d itens que não estão na biblioteca no banco de dados</string>
|
<string name="clear_database_source_item_count">%1$d itens que não estão na biblioteca no banco de dados</string>
|
||||||
<string name="database_clean">Nada a ser limpo</string>
|
<string name="database_clean">Nada a ser limpo</string>
|
||||||
<string name="extension_api_error">Erro ao obter a lista de extensões</string>
|
<string name="extension_api_error">Erro ao obter a lista de extensões</string>
|
||||||
@ -841,4 +841,5 @@
|
|||||||
<string name="track_delete_title">Remover o monitoramento do %s\?</string>
|
<string name="track_delete_title">Remover o monitoramento do %s\?</string>
|
||||||
<string name="track_delete_text">Isso irá remover o monitoramento localmente.</string>
|
<string name="track_delete_text">Isso irá remover o monitoramento localmente.</string>
|
||||||
<string name="track_delete_remote_text">Também remover do %s</string>
|
<string name="track_delete_remote_text">Também remover do %s</string>
|
||||||
|
<string name="delete_downloaded">Deletar os disponíveis offline</string>
|
||||||
</resources>
|
</resources>
|
@ -652,7 +652,7 @@
|
|||||||
<string name="download_queue_size_warning">Предупреждение: Большое количество загрузок может привести к замедлению работы источников и/или блокировке Tachiyomi. Нажмите для подробностей.</string>
|
<string name="download_queue_size_warning">Предупреждение: Большое количество загрузок может привести к замедлению работы источников и/или блокировке Tachiyomi. Нажмите для подробностей.</string>
|
||||||
<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 не библиотечных серий в базе данных</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>
|
||||||
@ -867,4 +867,5 @@
|
|||||||
<string name="track_delete_text">Это удалит отслеживание локально.</string>
|
<string name="track_delete_text">Это удалит отслеживание локально.</string>
|
||||||
<string name="track_delete_remote_text">Также удалить из %s</string>
|
<string name="track_delete_remote_text">Также удалить из %s</string>
|
||||||
<string name="action_ok">ОК</string>
|
<string name="action_ok">ОК</string>
|
||||||
|
<string name="delete_downloaded">Удалить загруженное</string>
|
||||||
</resources>
|
</resources>
|
@ -567,7 +567,7 @@
|
|||||||
<string name="cover_saved">Cobertedda sarvada</string>
|
<string name="cover_saved">Cobertedda sarvada</string>
|
||||||
<string name="manga_cover">Cobertedda</string>
|
<string name="manga_cover">Cobertedda</string>
|
||||||
<string name="tracking_guide">Ghia pro s\'arrastamentu</string>
|
<string name="tracking_guide">Ghia pro s\'arrastamentu</string>
|
||||||
<string name="categorized_display_settings">Impostatziones de ordinamentu e visualizatzione pro categoria</string>
|
<string name="categorized_display_settings">Impostatziones de ordinamentu pro categoria</string>
|
||||||
<string name="information_empty_category_dialog">Non tenes galu peruna categoria.</string>
|
<string name="information_empty_category_dialog">Non tenes galu peruna categoria.</string>
|
||||||
<string name="action_start_downloading_now">Incumintza a iscarrigare como</string>
|
<string name="action_start_downloading_now">Incumintza a iscarrigare como</string>
|
||||||
<string name="theme_tako">Tako</string>
|
<string name="theme_tako">Tako</string>
|
||||||
@ -643,7 +643,7 @@
|
|||||||
<string name="cancelled">Annullada</string>
|
<string name="cancelled">Annullada</string>
|
||||||
<string name="webtoon_side_padding_5">5%</string>
|
<string name="webtoon_side_padding_5">5%</string>
|
||||||
<string name="action_show_manga">Ammustra s\'elementu</string>
|
<string name="action_show_manga">Ammustra s\'elementu</string>
|
||||||
<string name="pref_landscape_zoom">Ismànnia s\'immàgine in orizontale</string>
|
<string name="pref_landscape_zoom">Ismànnia in automàticu sas immàgines largas</string>
|
||||||
<string name="action_display_cover_only_grid">Grìllia cun coberteddas ebbia</string>
|
<string name="action_display_cover_only_grid">Grìllia cun coberteddas ebbia</string>
|
||||||
<string name="pref_update_only_started">No incumintzadas</string>
|
<string name="pref_update_only_started">No incumintzadas</string>
|
||||||
<string name="pref_navigate_pan">Iscurre sas pàginas largas</string>
|
<string name="pref_navigate_pan">Iscurre sas pàginas largas</string>
|
||||||
@ -799,4 +799,36 @@
|
|||||||
<string name="pref_chapter_swipe">Iscurrimentu de capìtulu</string>
|
<string name="pref_chapter_swipe">Iscurrimentu de capìtulu</string>
|
||||||
<string name="pref_chapter_swipe_start">Atzione de iscurrimentu a manca</string>
|
<string name="pref_chapter_swipe_start">Atzione de iscurrimentu a manca</string>
|
||||||
<string name="pref_debug_info">Informatziones de depuratzione de còdighe</string>
|
<string name="pref_debug_info">Informatziones de depuratzione de còdighe</string>
|
||||||
|
<string name="manga_display_interval_title">Càrcula cada</string>
|
||||||
|
<string name="action_filter_interval_custom">Intervallu de recùperu personalizadu</string>
|
||||||
|
<string name="action_filter_interval_long">Recùpera cada mese (28 dies)</string>
|
||||||
|
<string name="action_filter_interval_dropped">Abbandonadu\? In ritardu de 20+ dies e 2 meses</string>
|
||||||
|
<string name="action_sort_next_updated">Agiornamentu imbente prevìdidu</string>
|
||||||
|
<string name="pref_update_only_in_release_period">Foras de su perìodu de publicatzione prevìdidu</string>
|
||||||
|
<string name="intervals_header">Intervallos</string>
|
||||||
|
<string name="manga_display_modified_interval_title">Imposta s\'agiornamentu pro cada</string>
|
||||||
|
<string name="manga_modify_interval_title">Modìfica s\'intervallu</string>
|
||||||
|
<string name="skipped_reason_not_in_release_period">Brincadu ca non bi fiat peruna publicatzione prevìdida oe</string>
|
||||||
|
<string name="action_set_interval">Imposta s\'intervallu</string>
|
||||||
|
<string name="action_filter_interval_late">Verìfica in ritardu de 10+ dies</string>
|
||||||
|
<string name="action_filter_interval_passed">Perìodu de controllu coladu</string>
|
||||||
|
<string name="manga_modify_calculated_interval_title">Personaliza s\'intervallu</string>
|
||||||
|
<plurals name="pref_update_release_leading_days">
|
||||||
|
<item quantity="one">%d die in antis</item>
|
||||||
|
<item quantity="other">%d dies in antis</item>
|
||||||
|
</plurals>
|
||||||
|
<plurals name="pref_update_release_following_days">
|
||||||
|
<item quantity="one">%d die a pustis</item>
|
||||||
|
<item quantity="other">%d dies a pustis</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="pref_update_release_grace_period_info">Unu perìodu de gràtzia bassu est cussigiadu pro minimare sa pressione subra sas fontes. Prus controllos pro un\'elementu si perdent, prus longu at a èssere s\'intervallu intre sos controllos cun unu màssimu de 28 dies.</string>
|
||||||
|
<string name="action_ok">AB</string>
|
||||||
|
<string name="pref_update_release_grace_period">Perìodu de gràtzia prevìdidu pro sa publicatzione</string>
|
||||||
|
<string name="track_delete_title">Bogare s\'arrastadore de %s\?</string>
|
||||||
|
<string name="track_delete_text">Custu at a bogare s\'arrastamentu locale.</string>
|
||||||
|
<string name="track_delete_remote_text">Boga fintzas dae %s</string>
|
||||||
|
<plurals name="day">
|
||||||
|
<item quantity="one">1 die</item>
|
||||||
|
<item quantity="other">%d dies</item>
|
||||||
|
</plurals>
|
||||||
</resources>
|
</resources>
|
@ -830,4 +830,5 @@
|
|||||||
<string name="skipped_reason_not_in_release_period">Atlandı çünkü bugün bir yayın beklenmiyordu</string>
|
<string name="skipped_reason_not_in_release_period">Atlandı çünkü bugün bir yayın beklenmiyordu</string>
|
||||||
<string name="track_delete_text">Bu, izlemeyi yerel olarak kaldıracak.</string>
|
<string name="track_delete_text">Bu, izlemeyi yerel olarak kaldıracak.</string>
|
||||||
<string name="track_delete_remote_text">Ayrıca şuradan da kaldır: %s</string>
|
<string name="track_delete_remote_text">Ayrıca şuradan da kaldır: %s</string>
|
||||||
|
<string name="manga_display_modified_interval_title">Güncelleme aralığını ayarla</string>
|
||||||
</resources>
|
</resources>
|
@ -616,7 +616,7 @@
|
|||||||
<string name="download_queue_size_warning">警告:批量下载可能导致图源变慢,甚至会使得它们屏蔽 Tachiyomi。点击了解详情。</string>
|
<string name="download_queue_size_warning">警告:批量下载可能导致图源变慢,甚至会使得它们屏蔽 Tachiyomi。点击了解详情。</string>
|
||||||
<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="database_clean">无需清理</string>
|
<string name="database_clean">无需清理</string>
|
||||||
<string name="clear_database_source_item_count">数据库中有 %1$d 部作品未添加到书架</string>
|
<string name="clear_database_source_item_count">数据库中有 %1$d 部作品未添加到书架</string>
|
||||||
<string name="extension_api_error">无法获取插件列表</string>
|
<string name="extension_api_error">无法获取插件列表</string>
|
||||||
@ -797,4 +797,5 @@
|
|||||||
<string name="track_delete_title">要删除 %s 的记录吗?</string>
|
<string name="track_delete_title">要删除 %s 的记录吗?</string>
|
||||||
<string name="track_delete_remote_text">同时删除 %s 上的数据</string>
|
<string name="track_delete_remote_text">同时删除 %s 上的数据</string>
|
||||||
<string name="track_delete_text">将会在本地删除进度记录的关联。</string>
|
<string name="track_delete_text">将会在本地删除进度记录的关联。</string>
|
||||||
|
<string name="delete_downloaded">删除已下载章节</string>
|
||||||
</resources>
|
</resources>
|
@ -616,7 +616,7 @@
|
|||||||
<string name="download_queue_size_warning">警告:大量批次下載可能壅塞來源並 (或) 使其封鎖 Tachiyomi。輕觸以瞭解詳情。</string>
|
<string name="download_queue_size_warning">警告:大量批次下載可能壅塞來源並 (或) 使其封鎖 Tachiyomi。輕觸以瞭解詳情。</string>
|
||||||
<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 部作品不屬於藏書</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>
|
||||||
@ -631,7 +631,7 @@
|
|||||||
<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">顯示作品</string>
|
<string name="action_show_manga">顯示作品</string>
|
||||||
<string name="pref_landscape_zoom">縮放橫向圖片</string>
|
<string name="pref_landscape_zoom">自動縮放寬頁</string>
|
||||||
<string name="pref_navigate_pan">導覽寬頁時先平移後翻頁</string>
|
<string name="pref_navigate_pan">導覽寬頁時先平移後翻頁</string>
|
||||||
<string name="action_display_cover_only_grid">純封面格狀</string>
|
<string name="action_display_cover_only_grid">純封面格狀</string>
|
||||||
<string name="pref_update_only_started">無已讀的章節</string>
|
<string name="pref_update_only_started">無已讀的章節</string>
|
||||||
@ -785,4 +785,8 @@
|
|||||||
<string name="pref_chapter_swipe">目錄滑動動作</string>
|
<string name="pref_chapter_swipe">目錄滑動動作</string>
|
||||||
<string name="pref_library_columns_per_row">每列 %d 欄</string>
|
<string name="pref_library_columns_per_row">每列 %d 欄</string>
|
||||||
<string name="action_ok">確定</string>
|
<string name="action_ok">確定</string>
|
||||||
|
<string name="delete_downloaded">刪除舊有下載章節</string>
|
||||||
|
<string name="track_delete_title">移除「%s」歷程平台?</string>
|
||||||
|
<string name="track_delete_text">這將在本機上解除登錄該歷程平台。</string>
|
||||||
|
<string name="track_delete_remote_text">同時移除「%s」上的資料</string>
|
||||||
</resources>
|
</resources>
|
@ -12,6 +12,7 @@
|
|||||||
<string name="manga">Library entries</string>
|
<string name="manga">Library entries</string>
|
||||||
<string name="chapters">Chapters</string>
|
<string name="chapters">Chapters</string>
|
||||||
<string name="track">Tracking</string>
|
<string name="track">Tracking</string>
|
||||||
|
<string name="delete_downloaded">Delete downloaded</string>
|
||||||
<string name="history">History</string>
|
<string name="history">History</string>
|
||||||
|
|
||||||
<!-- Screen titles -->
|
<!-- Screen titles -->
|
||||||
@ -380,7 +381,7 @@
|
|||||||
<string name="tapping_inverted_vertical">Vertical</string>
|
<string name="tapping_inverted_vertical">Vertical</string>
|
||||||
<string name="tapping_inverted_both">Both</string>
|
<string name="tapping_inverted_both">Both</string>
|
||||||
<string name="pref_reader_actions">Actions</string>
|
<string name="pref_reader_actions">Actions</string>
|
||||||
<string name="pref_read_with_long_tap">Show on long tap</string>
|
<string name="pref_read_with_long_tap">Show actions on long tap</string>
|
||||||
<string name="pref_create_folder_per_manga">Save pages into separate folders</string>
|
<string name="pref_create_folder_per_manga">Save pages into separate folders</string>
|
||||||
<string name="pref_create_folder_per_manga_summary">Creates folders according to entries\' title</string>
|
<string name="pref_create_folder_per_manga_summary">Creates folders according to entries\' title</string>
|
||||||
<string name="pref_reader_theme">Background color</string>
|
<string name="pref_reader_theme">Background color</string>
|
||||||
@ -474,7 +475,7 @@
|
|||||||
<item quantity="one">Next unread chapter</item>
|
<item quantity="one">Next unread chapter</item>
|
||||||
<item quantity="other">Next %d unread chapters</item>
|
<item quantity="other">Next %d unread chapters</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="download_ahead_info">Only works on entries in library and if the current chapter plus the next one are already downloaded</string>
|
<string name="download_ahead_info">Only works if the current chapter + the next one are already downloaded.</string>
|
||||||
<string name="save_chapter_as_cbz">Save as CBZ archive</string>
|
<string name="save_chapter_as_cbz">Save as CBZ archive</string>
|
||||||
<string name="split_tall_images">Split tall images</string>
|
<string name="split_tall_images">Split tall images</string>
|
||||||
<string name="split_tall_images_summary">Improves reader performance</string>
|
<string name="split_tall_images_summary">Improves reader performance</string>
|
||||||
@ -570,7 +571,7 @@
|
|||||||
<string name="used_cache">Used: %1$s</string>
|
<string name="used_cache">Used: %1$s</string>
|
||||||
<string name="cache_deleted">Cache cleared. %1$d files have been deleted</string>
|
<string name="cache_deleted">Cache cleared. %1$d files have been deleted</string>
|
||||||
<string name="cache_delete_error">Error occurred while clearing</string>
|
<string name="cache_delete_error">Error occurred while clearing</string>
|
||||||
<string name="pref_auto_clear_chapter_cache">Clear chapter cache on app close</string>
|
<string name="pref_auto_clear_chapter_cache">Clear chapter cache on app launch</string>
|
||||||
<string name="pref_invalidate_download_cache">Invalidate downloads index</string>
|
<string name="pref_invalidate_download_cache">Invalidate downloads index</string>
|
||||||
<string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string>
|
<string name="pref_invalidate_download_cache_summary">Force app to recheck downloaded chapters</string>
|
||||||
<string name="pref_clear_database">Clear database</string>
|
<string name="pref_clear_database">Clear database</string>
|
||||||
|
@ -21,6 +21,8 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":core"))
|
||||||
|
|
||||||
// Compose
|
// Compose
|
||||||
implementation(platform(compose.bom))
|
implementation(platform(compose.bom))
|
||||||
implementation(compose.activity)
|
implementation(compose.activity)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user