Compare commits

..
13 Commits
Author SHA1 Message Date
FooIbar f51da1a948 Prepare for release 1.14.5
Releases / build (push) Has been cancelled
2025-10-19 21:18:11 +08:00
FooIbar c1ac592855 [Reader] Show gallery title & fix status bar color 2025-10-19 12:41:17 +08:00
FooIbar 371103908b Fix flickering loops in reader
Opt out activity recreation for size-based config changes as they are
handled by Compose.
2025-10-16 19:19:40 +08:00
FooIbar a2a029bb28 Fix unnecessary recompositions
`BaseGalleryInfo` is used as part of remember keys.
2025-10-16 19:19:40 +08:00
renovate[bot] 9266fba415 Update dependency libarchive to v3.8.2 (#2678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-16 00:58:36 +00:00
FooIbar 0963e2f564 Fix reader settings crash with custom orientation 2025-10-15 18:11:29 +08:00
renovate[bot] 72a5906a9b Lock file maintenance (#2676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-15 02:13:59 +00:00
renovate[bot] 4dbd54c495 Update dependency com.squareup.okio:okio to v3.16.2 (#2675)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 20:06:47 +00:00
renovate[bot] 6219acb15c Update dependency org.jetbrains.compose to v1.9.1 (#2672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-14 13:53:25 +00:00
renovate[bot] c4179bef5d Update aboutlibraries to v13.1.0 (#2670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 20:52:02 +00:00
renovate[bot] 117a1eaab8 Fix -Ofast deprecation 2025-10-13 17:31:15 +08:00
FooIbar 78e31e4fb9 Remove indent from compiler flags 2025-10-13 00:14:07 +08:00
FooIbar 3da86fd745 Prepare for next iteration 2025-10-12 21:32:38 +08:00
19 changed files with 277 additions and 193 deletions

No files matched your search

+13
View File
@@ -1,5 +1,18 @@
# 变更日志
## [1.14.5] - 2025-10-19
### 改进
* [阅读器] 显示画廊标题
* [阅读器] 显示菜单时改变标题栏颜色
### Bug 修复
* 横屏模式下打开阅读器设置会闪退 [#2673](https://github.com/FooIbar/EhViewer/issues/2673)
* 强制横屏时竖直拿取设备加载图片会横竖屏乱跳 [#2674](https://github.com/FooIbar/EhViewer/issues/2674)
## [1.14.4] - 2025-10-12
### 改进
+1 -1
View File
@@ -57,7 +57,7 @@ android {
defaultConfig {
applicationId = "moe.tarsin.ehviewer"
versionCode = 180063
versionName = "1.14.4"
versionName = "1.14.5"
// versionNameSuffix = "-SNAPSHOT"
buildConfigField("String", "RAW_VERSION_NAME", "\"$versionName${versionNameSuffix.orEmpty()}\"")
buildConfigField("String", "COMMIT_SHA", "\"$commitSha\"")
+1 -1
View File
@@ -39,7 +39,7 @@
<activity
android:name=".ui.MainActivity"
android:banner="@mipmap/ic_leanback_banner"
android:configChanges="screenSize"
android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/AppTheme.Splash"
+12 -12
View File
@@ -4,17 +4,17 @@ include(ExternalProject)
include(FetchContent)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Ofast -fvisibility=hidden -fvisibility-inlines-hidden -funroll-loops -flto \
-mllvm -polly \
-mllvm -polly-run-dce \
-mllvm -polly-run-inliner \
-mllvm -polly-isl-arg=--no-schedule-serialize-sccs \
-mllvm -polly-ast-use-context \
-mllvm -polly-detect-keep-going \
-mllvm -polly-position=before-vectorizer \
-mllvm -polly-vectorizer=stripmine \
-mllvm -polly-detect-profitability-min-per-loop-insts=40 \
-mllvm -polly-invariant-load-hoisting")
string(CONCAT CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -ffast-math -fvisibility=hidden -fvisibility-inlines-hidden -funroll-loops -flto "
"-mllvm -polly "
"-mllvm -polly-run-dce "
"-mllvm -polly-run-inliner "
"-mllvm -polly-isl-arg=--no-schedule-serialize-sccs "
"-mllvm -polly-ast-use-context "
"-mllvm -polly-detect-keep-going "
"-mllvm -polly-position=before-vectorizer "
"-mllvm -polly-vectorizer=stripmine "
"-mllvm -polly-detect-profitability-min-per-loop-insts=40 "
"-mllvm -polly-invariant-load-hoisting")
endif (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
option(BUILD_TESTING OFF)
@@ -96,7 +96,7 @@ set(LIBARCHIVE_PATCH
FetchContent_Declare(
libarchive
GIT_REPOSITORY https://github.com/libarchive/libarchive.git
GIT_TAG v3.8.1
GIT_TAG v3.8.2
GIT_SHALLOW 1
PATCH_COMMAND git apply --check -R ${LIBARCHIVE_PATCH} || git apply ${LIBARCHIVE_PATCH}
)
@@ -194,6 +194,10 @@ object Settings : DataStorePreferences(null) {
if (pref[downloadFilterMode] == DownloadsFilterMode.ARTIST.flag && pref[recentDownloadLabel] == null) {
pref[recentDownloadLabel] = ""
}
val orientation = pref[orientationMode]
if (OrientationType.entries.none { it.prefValue == orientation }) {
pref.remove(orientationMode)
}
}
}
@@ -17,8 +17,10 @@ package com.hippo.ehviewer.gallery
import arrow.autoCloseScope
import com.ehviewer.core.files.openFileDescriptor
import com.ehviewer.core.model.GalleryInfo
import com.ehviewer.core.util.logcat
import com.hippo.ehviewer.Settings.archivePasswds
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.image.ImageSource
import com.hippo.ehviewer.image.byteBufferSource
import com.hippo.ehviewer.jni.closeArchive
@@ -40,7 +42,7 @@ typealias PasswdProvider = suspend (PasswdInvalidator) -> String
suspend inline fun <T> useArchivePageLoader(
file: Path,
gid: Long = 0,
info: GalleryInfo? = null,
startPage: Int = 0,
hasAds: Boolean = false,
crossinline passwdProvider: PasswdProvider,
@@ -49,7 +51,7 @@ suspend inline fun <T> useArchivePageLoader(
coroutineScope {
val pfd = install(file.openFileDescriptor("r"))
val size = install(
{ openArchive(pfd.fd, pfd.statSize, gid == 0L || file.name.endsWith(".zip")) },
{ openArchive(pfd.fd, pfd.statSize, info == null || file.name.endsWith(".zip")) },
{ _, _ -> closeArchive() },
)
check(size > 0) { "Archive have no content!" }
@@ -57,8 +59,14 @@ suspend inline fun <T> useArchivePageLoader(
archivePasswds += passwdProvider(::providePassword)
}
val loader = install(
object : PageLoader(this, gid, startPage, size, hasAds) {
override val title by lazy { FileUtils.getNameFromFilename(file.displayName)!! }
object : PageLoader(this, info, startPage, size, hasAds) {
override val title by lazy {
if (info != null) {
EhUtils.getSuitableTitle(info)
} else {
FileUtils.getNameFromFilename(file.displayName)!!
}
}
override fun getImageExtension(index: Int) = getExtension(index)
@@ -24,7 +24,7 @@ suspend inline fun <T> useEhPageLoader(
)
queen.awaitReady()
val loader = install(
object : PageLoader(this, info.gid, startPage, queen.size, info.hasAds) {
object : PageLoader(this, info, startPage, queen.size, info.hasAds) {
override val title by lazy { EhUtils.getSuitableTitle(info) }
override fun getImageExtension(index: Int) = queen.getExtension(index)
@@ -4,6 +4,7 @@ import androidx.collection.SieveCache
import androidx.collection.mutableIntObjectMapOf
import arrow.fx.coroutines.ExitCase
import arrow.fx.coroutines.bracketCase
import com.ehviewer.core.model.GalleryInfo
import com.ehviewer.core.util.isAtLeastO
import com.ehviewer.core.util.withNonCancellableContext
import com.hippo.ehviewer.EhDB
@@ -35,7 +36,7 @@ private val progressScope = CoroutineScope(Dispatchers.IO)
private const val MAX_CACHE_SIZE = 512 * 1024 * 1024
private const val MIN_CACHE_SIZE = 256 * 1024 * 1024
abstract class PageLoader(val scope: CoroutineScope, val gid: Long, startPage: Int, val size: Int, val hasAds: Boolean = false) : AutoCloseable {
abstract class PageLoader(val scope: CoroutineScope, val info: GalleryInfo?, startPage: Int, val size: Int, val hasAds: Boolean = false) : AutoCloseable {
var startPage = startPage.coerceIn(0, size - 1)
private val jobs = mutableIntObjectMapOf<Job>()
@@ -111,14 +112,14 @@ abstract class PageLoader(val scope: CoroutineScope, val gid: Long, startPage: I
override fun close() {
lock.write { cache.evictAll() }
if (gid != 0L) {
info?.run {
progressScope.launch {
EhDB.putReadProgress(gid, startPage)
}
}
}
protected abstract val title: String
abstract val title: String
protected abstract fun getImageExtension(index: Int): String?
@@ -88,7 +88,7 @@ fun ColorFilterSetting() = Column(modifier = Modifier.verticalScroll(rememberScr
SpinnerChoice(
title = stringResource(id = R.string.pref_color_filter_mode),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.color_filter_modes),
values = arrayOf("0", "1", "2", "3", "4", "5"),
values = listOf(0, 1, 2, 3, 4, 5),
field = Settings.colorFilterMode.asMutableState(),
)
SwitchChoice(
@@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.integerArrayResource
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import com.ehviewer.core.i18n.R
@@ -21,7 +22,7 @@ fun ReaderGeneralSetting() = Column(modifier = Modifier.verticalScroll(rememberS
SpinnerChoice(
title = stringResource(id = R.string.pref_reader_theme),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.reader_themes),
values = stringArrayResource(id = com.hippo.ehviewer.R.array.reader_themes_values),
values = integerArrayResource(id = com.hippo.ehviewer.R.array.reader_themes_values).toList(),
field = Settings.readerTheme.asMutableState(),
)
SwitchChoice(
@@ -13,25 +13,28 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.integerArrayResource
import androidx.compose.ui.res.stringArrayResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.ehviewer.core.i18n.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
@Composable
fun ReaderModeSetting(isWebtoon: Boolean) = Column(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) {
SpinnerChoice(
title = stringResource(id = R.string.pref_category_reading_mode),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.viewers_selector),
values = arrayOf("0", "1", "2", "3", "4", "5"),
values = ReadingModeType.entries.map { it.prefValue },
field = Settings.readingMode.asMutableState(),
)
SpinnerChoice(
title = stringResource(id = R.string.rotation_type),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.rotation_type),
values = arrayOf("0", "8", "16", "24", "32", "40", "48"),
values = OrientationType.entries.map { it.prefValue },
field = Settings.orientationMode.asMutableState(),
)
Spacer(modifier = Modifier.size(16.dp))
@@ -55,7 +58,7 @@ private fun PagerSetting() = Column {
SpinnerChoice(
title = stringResource(id = R.string.pref_viewer_nav),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.pager_nav),
values = arrayOf("0", "1", "2", "3", "4", "5"),
values = listOf(0, 1, 2, 3, 4, 5),
field = pagerNav,
)
AnimatedVisibility(visible = pagerNav.value != 5) {
@@ -63,7 +66,7 @@ private fun PagerSetting() = Column {
SpinnerChoice(
title = stringResource(id = R.string.pref_read_with_tapping_inverted),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.invert_tapping_mode),
values = arrayOf("0", "1", "2", "3"),
values = listOf(0, 1, 2, 3),
field = Settings.readerPagerNavInverted.asMutableState(),
)
SwitchChoice(
@@ -76,7 +79,7 @@ private fun PagerSetting() = Column {
SpinnerChoice(
title = stringResource(id = R.string.pref_image_scale_type),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.image_scale_type),
values = arrayOf("1", "2", "3", "4", "5", "6"),
values = listOf(1, 2, 3, 4, 5, 6),
field = scaleType,
)
AnimatedVisibility(visible = scaleType.value == 1) {
@@ -88,7 +91,7 @@ private fun PagerSetting() = Column {
SpinnerChoice(
title = stringResource(id = R.string.pref_zoom_start),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.zoom_start),
values = arrayOf("1", "2", "3", "4"),
values = listOf(1, 2, 3, 4),
field = Settings.zoomStart.asMutableState(),
)
SwitchChoice(
@@ -108,21 +111,21 @@ private fun WebtoonSetting() = Column {
SpinnerChoice(
title = stringResource(id = R.string.pref_viewer_nav),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.webtoon_nav),
values = arrayOf("0", "1", "2", "3", "4", "5"),
values = listOf(0, 1, 2, 3, 4, 5),
field = webtoonNav,
)
AnimatedVisibility(visible = webtoonNav.value != 5) {
SpinnerChoice(
title = stringResource(id = R.string.pref_read_with_tapping_inverted),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.invert_tapping_mode),
values = arrayOf("0", "1", "2", "3"),
values = listOf(0, 1, 2, 3),
field = Settings.readerWebtoonNavInverted.asMutableState(),
)
}
SpinnerChoice(
title = stringResource(id = R.string.pref_webtoon_side_padding),
entries = stringArrayResource(id = com.hippo.ehviewer.R.array.webtoon_side_padding),
values = stringArrayResource(id = com.hippo.ehviewer.R.array.webtoon_side_padding_values),
values = integerArrayResource(id = com.hippo.ehviewer.R.array.webtoon_side_padding_values).toList(),
field = Settings.webtoonSidePadding.asMutableState(),
)
SwitchChoice(
@@ -13,14 +13,11 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.displayCutout
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.windowInsetsTopHeight
import androidx.compose.foundation.lazy.layout.LazyLayoutCacheWindow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.pager.rememberPagerState
@@ -53,7 +50,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.keepScreenOn
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.zIndex
import arrow.core.Either
import arrow.core.Either.Companion.catch
import arrow.core.raise.ensure
@@ -82,7 +78,6 @@ import com.hippo.ehviewer.gallery.useEhPageLoader
import com.hippo.ehviewer.ui.MainActivity
import com.hippo.ehviewer.ui.Screen
import com.hippo.ehviewer.ui.theme.EhTheme
import com.hippo.ehviewer.ui.theme.scrim
import com.hippo.ehviewer.ui.tools.DialogState
import com.hippo.ehviewer.ui.tools.awaitInputText
import com.hippo.ehviewer.ui.tools.dialog
@@ -131,15 +126,11 @@ fun AnimatedVisibilityScope.ReaderScreen(args: ReaderScreenArgs, navigator: Dest
val uiController = rememberSystemUiController()
DisposableEffect(uiController) {
val lightStatusBar = uiController.statusBarDarkContentEnabled
uiController.statusBarDarkContentEnabled = bgColor == Color.White
onDispose {
uiController.statusBarDarkContentEnabled = lightStatusBar
}
}
LaunchedEffect(uiController) {
snapshotFlow { bgColor }.collect {
uiController.statusBarDarkContentEnabled = it == Color.White
}
}
Await(
block = asyncInVM(args) { alive ->
@@ -184,7 +175,7 @@ fun AnimatedVisibilityScope.ReaderScreen(args: ReaderScreenArgs, navigator: Dest
}
@Composable
context(activity: MainActivity, _: SnackbarHostState, _: DialogState, _: CoroutineScope)
context(activity: MainActivity, _: SnackbarHostState, _: DialogState, _: CoroutineScope, _: DestinationsNavigator)
fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
LaunchedEffect(Unit) {
val orientation = activity.requestedOrientation
@@ -240,18 +231,14 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
val bgColor by collectBackgroundColorAsState()
syncState.Sync(isWebtoon) { appbarVisible = false }
if (fullscreen) {
LaunchedEffect(Unit) {
snapshotFlow { appbarVisible }.collect {
uiController.isSystemBarsVisible = it
}
val bgColor by collectBackgroundColorAsState()
val isDarkTheme = isSystemInDarkTheme()
LaunchedEffect(isDarkTheme) {
snapshotFlow { appbarVisible }.collect {
uiController.isSystemBarsVisible = it || !fullscreen
uiController.statusBarDarkContentEnabled = if (it) !isDarkTheme else bgColor == Color.White
}
Box(
Modifier.windowInsetsTopHeight(WindowInsets.statusBars).fillMaxWidth()
.align(Alignment.TopCenter).background(bgColor.scrim()).zIndex(1f),
)
}
var showNavigationOverlay by remember {
val showOnStart = Settings.showNavigationOverlayNewUser.value || Settings.showNavigationOverlayOnStart.value
@@ -353,6 +340,7 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
}
ReaderAppBars(
visible = appbarVisible,
title = pageLoader.title,
isRtl = readingMode == ReadingModeType.RIGHT_TO_LEFT,
showSeekBar = showSeekbar,
currentPage = syncState.sliderValue,
@@ -383,7 +371,6 @@ fun ReaderScreen(pageLoader: PageLoader, info: BaseGalleryInfo?) {
}
}
},
modifier = Modifier.align(Alignment.BottomCenter),
)
}
}
@@ -395,7 +382,7 @@ suspend inline fun <T> usePageLoader(args: ReaderScreenArgs, crossinline block:
val page = args.page.takeUnless { it == -1 } ?: EhDB.getReadProgress(info.gid)
val archive = DownloadManager.getDownloadInfo(info.gid)?.archiveFile
if (archive != null) {
useArchivePageLoader(archive, info.gid, page, info.hasAds, { error("Managed Archive have password???") }, block)
useArchivePageLoader(archive, info, page, info.hasAds, { error("Managed Archive have password???") }, block)
} else {
useEhPageLoader(info, page, block)
}
@@ -28,10 +28,10 @@ import androidx.compose.ui.unit.dp
import com.ehviewer.core.ui.component.Slider
@Composable
fun SpinnerChoice(title: String, entries: Array<String>, values: Array<String>, field: MutableState<Int>) {
fun SpinnerChoice(title: String, entries: Array<String>, values: List<Int>, field: MutableState<Int>) {
var value by field
var dropdown by remember { mutableStateOf(false) }
val data = remember { entries zip values.map { v -> v.toInt() } }
val data = remember { entries zip values }
Row(
modifier = Modifier.fillMaxWidth().height(48.dp).clickable { dropdown = true }.padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -6,47 +6,72 @@ import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.systemBarsIgnoringVisibility
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.BottomAppBarDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import com.hippo.ehviewer.ui.main.NavigationIcon
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
private val animationSpec = tween<IntOffset>(200)
@Composable
fun ReaderAppBars(
context(navigator: DestinationsNavigator)
fun BoxScope.ReaderAppBars(
visible: Boolean,
title: String,
isRtl: Boolean,
showSeekBar: Boolean,
currentPage: Int,
totalPages: Int,
onSliderValueChange: (Int) -> Unit,
onClickSettings: () -> Unit,
modifier: Modifier = Modifier,
) = AnimatedVisibility(
visible = visible,
modifier = modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Horizontal)),
enter = slideInVertically(initialOffsetY = { it }, animationSpec = animationSpec),
exit = slideOutVertically(targetOffsetY = { it }, animationSpec = animationSpec),
) {
val toolbarColor = BottomAppBarDefaults.containerColor.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
if (showSeekBar && totalPages > 1) {
ChapterNavigator(
isRtl = isRtl,
currentPage = currentPage,
totalPages = totalPages,
onSliderValueChange = onSliderValueChange,
containerColor = toolbarColor,
)
val backgroundColor = BottomAppBarDefaults.containerColor.copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f)
AnimatedVisibility(
visible = visible,
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBarsIgnoringVisibility.only(WindowInsetsSides.Horizontal)).align(Alignment.TopStart),
enter = slideInVertically(initialOffsetY = { -it }, animationSpec = animationSpec),
exit = slideOutVertically(targetOffsetY = { -it }, animationSpec = animationSpec),
) {
TopAppBar(
title = { Text(text = title, maxLines = 2, overflow = TextOverflow.Ellipsis) },
colors = TopAppBarDefaults.topAppBarColors(containerColor = backgroundColor),
navigationIcon = { NavigationIcon() },
)
}
AnimatedVisibility(
visible = visible,
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBarsIgnoringVisibility.only(WindowInsetsSides.Horizontal)).align(Alignment.BottomStart),
enter = slideInVertically(initialOffsetY = { it }, animationSpec = animationSpec),
exit = slideOutVertically(targetOffsetY = { it }, animationSpec = animationSpec),
) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
if (showSeekBar && totalPages > 1) {
ChapterNavigator(
isRtl = isRtl,
currentPage = currentPage,
totalPages = totalPages,
onSliderValueChange = onSliderValueChange,
containerColor = backgroundColor,
)
}
BottomReaderBar(onClickSettings = onClickSettings, containerColor = backgroundColor)
}
BottomReaderBar(onClickSettings = onClickSettings, containerColor = toolbarColor)
}
}
+4 -4
View File
@@ -220,12 +220,12 @@
<item>@string/automatic_background</item>
</string-array>
<string-array name="reader_themes_values">
<integer-array name="reader_themes_values">
<item>1</item>
<item>2</item>
<item>0</item>
<item>3</item>
</string-array>
</integer-array>
<string-array name="color_filter_modes" tools:ignore="InconsistentArrays">
<item>@string/label_default</item>
@@ -293,14 +293,14 @@
<item>@string/webtoon_side_padding_25</item>
</string-array>
<string-array name="webtoon_side_padding_values">
<integer-array name="webtoon_side_padding_values">
<item>0</item>
<item>5</item>
<item>10</item>
<item>15</item>
<item>20</item>
<item>25</item>
</string-array>
</integer-array>
<string-array name="update_frequency">
<item>@string/update_frequency_never</item>
+99 -108
View File
@@ -2,21 +2,6 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "addr2line"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "aho-corasick"
version = "1.1.3"
@@ -70,21 +55,6 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "backtrace"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-link 0.2.1",
]
[[package]]
name = "base64"
version = "0.22.1"
@@ -345,9 +315,9 @@ dependencies = [
[[package]]
name = "env_filter"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2"
dependencies = [
"log",
]
@@ -468,27 +438,21 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
"wasi",
]
[[package]]
name = "getrandom"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi 0.14.7+wasi-0.2.4",
"wasip2",
]
[[package]]
name = "gimli"
version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "h2"
version = "0.4.12"
@@ -793,17 +757,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "io-uring"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b"
dependencies = [
"bitflags",
"cfg-if",
"libc",
]
[[package]]
name = "ipnet"
version = "2.11.0"
@@ -923,15 +876,6 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
]
[[package]]
name = "mio"
version = "1.0.4"
@@ -939,7 +883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"wasi 0.11.1+wasi-snapshot-preview1",
"wasi",
"windows-sys 0.59.0",
]
@@ -1098,15 +1042,6 @@ dependencies = [
"syn",
]
[[package]]
name = "object"
version = "0.37.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@@ -1267,9 +1202,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "regex"
version = "1.12.1"
version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433"
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
dependencies = [
"aho-corasick",
"memchr",
@@ -1279,9 +1214,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.12"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
@@ -1296,15 +1231,15 @@ checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da"
[[package]]
name = "regex-syntax"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "reqwest"
version = "0.12.23"
version = "0.12.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb"
checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
dependencies = [
"base64",
"bytes",
@@ -1354,12 +1289,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustix"
version = "1.1.2"
@@ -1582,12 +1511,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "socket2"
version = "0.6.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
dependencies = [
"libc",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -1661,7 +1590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
dependencies = [
"fastrand",
"getrandom 0.3.3",
"getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.61.2",
@@ -1724,27 +1653,24 @@ source = "git+https://github.com/FooIbar/tl.git#13ed128e35ce04c4f16c41cb1e38347d
[[package]]
name = "tokio"
version = "1.47.1"
version = "1.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
dependencies = [
"backtrace",
"bytes",
"io-uring",
"libc",
"mio",
"pin-project-lite",
"slab",
"socket2",
"tokio-macros",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
@@ -1967,15 +1893,6 @@ version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]]
name = "wasi"
version = "0.14.7+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
dependencies = [
"wasip2",
]
[[package]]
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
@@ -2197,6 +2114,15 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-sys"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.5",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -2230,13 +2156,30 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link 0.2.1",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
"windows_i686_gnullvm 0.53.1",
"windows_i686_msvc 0.53.1",
"windows_x86_64_gnu 0.53.1",
"windows_x86_64_gnullvm 0.53.1",
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -2249,6 +2192,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -2261,6 +2210,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -2273,12 +2228,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -2291,6 +2258,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -2303,6 +2276,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -2315,6 +2294,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -2327,6 +2312,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "0.7.13"
@@ -39,4 +39,54 @@ open class BaseGalleryInfo(
override var favoriteSlot: Int = NOT_FAVORITED,
override var favoriteName: String? = null,
override var favoriteNote: String? = null,
) : GalleryInfo
) : GalleryInfo {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BaseGalleryInfo) return false
if (gid != other.gid) return false
if (category != other.category) return false
if (disowned != other.disowned) return false
if (rating != other.rating) return false
if (rated != other.rated) return false
if (pages != other.pages) return false
if (thumbWidth != other.thumbWidth) return false
if (thumbHeight != other.thumbHeight) return false
if (favoriteSlot != other.favoriteSlot) return false
if (token != other.token) return false
if (title != other.title) return false
if (titleJpn != other.titleJpn) return false
if (thumbKey != other.thumbKey) return false
if (posted != other.posted) return false
if (uploader != other.uploader) return false
if (simpleTags != other.simpleTags) return false
if (simpleLanguage != other.simpleLanguage) return false
if (favoriteName != other.favoriteName) return false
if (favoriteNote != other.favoriteNote) return false
return true
}
override fun hashCode(): Int {
var result = gid.hashCode()
result = 31 * result + category
result = 31 * result + disowned.hashCode()
result = 31 * result + rating.hashCode()
result = 31 * result + rated.hashCode()
result = 31 * result + pages
result = 31 * result + thumbWidth
result = 31 * result + thumbHeight
result = 31 * result + favoriteSlot
result = 31 * result + token.hashCode()
result = 31 * result + (title?.hashCode() ?: 0)
result = 31 * result + (titleJpn?.hashCode() ?: 0)
result = 31 * result + (thumbKey?.hashCode() ?: 0)
result = 31 * result + (posted?.hashCode() ?: 0)
result = 31 * result + (uploader?.hashCode() ?: 0)
result = 31 * result + (simpleTags?.hashCode() ?: 0)
result = 31 * result + (simpleLanguage?.hashCode() ?: 0)
result = 31 * result + (favoriteName?.hashCode() ?: 0)
result = 31 * result + (favoriteNote?.hashCode() ?: 0)
return result
}
}
@@ -9,6 +9,7 @@ open class Snapshot internal constructor(private val delegate: Preferences) {
}
class MutableSnapshot internal constructor(private val delegate: MutablePreferences) : Snapshot(delegate) {
fun <T> remove(pref: PrefDelegate<T>): T = delegate.remove(pref.key)
operator fun <T> set(pref: PrefDelegate<T>, value: T) {
if (value == null) {
delegate.remove(pref.key)
+3 -3
View File
@@ -1,5 +1,5 @@
[versions]
aboutlibraries = "13.0.0"
aboutlibraries = "13.1.0"
accompanist = "0.37.3"
agp = "8.13.0"
androidx-activity = "1.12.0-alpha09"
@@ -16,7 +16,7 @@ androidx-work = "2.11.0-rc01"
arrow = "2.1.2"
coil = "3.3.0"
compose-bom = "2025.10.00"
compose-multiplatform = "1.9.0"
compose-multiplatform = "1.9.1"
compose-destinations = "2.3.0"
compose-preference = "2.1.0"
kotlin = "2.2.20"
@@ -28,7 +28,7 @@ ksp = "2.2.20-2.0.4"
ktor = "3.3.1"
moko-resources = "0.25.1"
okhttp = "5.2.1"
okio = "3.16.1"
okio = "3.16.2"
splitties = "3.0.0"
spotless = "8.0.0"
telephoto = "0.18.0"