From ebb690cbe7bb4b41a9cfcd5130ac92e50276438b Mon Sep 17 00:00:00 2001 From: arkon Date: Fri, 4 Aug 2023 18:05:02 -0400 Subject: [PATCH] Migrate bottom reader menu to Compose (cherry picked from commit 8680accd8e6f458a662dd5454bbcdcde482ce0a7) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt # app/src/main/res/layout/reader_activity.xml --- .../presentation/reader/BottomReaderBar.kt | 155 ++++++++ .../presentation/reader/ChapterListDialog.kt | 84 ++++ .../presentation/reader/ChapterNavigator.kt | 17 +- .../tachiyomi/ui/manga/EditMangaDialog.kt | 2 +- .../ui/manga/merged/EditMergedMangaHolder.kt | 2 +- .../tachiyomi/ui/reader/ReaderActivity.kt | 362 +++++++----------- .../tachiyomi/ui/reader/ReaderViewModel.kt | 60 ++- .../ui/reader/chapter/ReaderChapterAdapter.kt | 21 - .../ui/reader/chapter/ReaderChapterDialog.kt | 80 ---- .../ui/reader/chapter/ReaderChapterItem.kt | 133 +------ .../tachiyomi/util/view/ViewExtensions.kt | 34 -- .../ui/metadata/adapters/MetadataUIUtil.kt | 28 +- .../main/res/drawable/ic_settings_24dp.xml | 9 - app/src/main/res/layout/reader_activity.xml | 124 +----- 14 files changed, 466 insertions(+), 645 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt create mode 100644 app/src/main/java/eu/kanade/presentation/reader/ChapterListDialog.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterAdapter.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterDialog.kt delete mode 100644 app/src/main/res/drawable/ic_settings_24dp.xml diff --git a/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt b/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt new file mode 100644 index 000000000..1b448ac20 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/BottomReaderBar.kt @@ -0,0 +1,155 @@ +package eu.kanade.presentation.reader + +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +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.icons.Icons +import androidx.compose.material.icons.outlined.FormatListNumbered +import androidx.compose.material.icons.outlined.Public +import androidx.compose.material.icons.outlined.Settings +import androidx.compose.material.icons.outlined.Share +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.surfaceColorAtElevation +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.reader.setting.OrientationType +import eu.kanade.tachiyomi.ui.reader.setting.ReaderBottomButton +import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType + +@Composable +fun BottomReaderBar( + // SY --> + enabledButtons: Set, + // SY <-- + readingMode: ReadingModeType, + onClickReadingMode: () -> Unit, + orientationMode: OrientationType, + onClickOrientationMode: () -> Unit, + cropEnabled: Boolean, + onClickCropBorder: () -> Unit, + onClickSettings: () -> Unit, + // SY --> + isHttpSource: Boolean, + dualPageSplitEnabled: Boolean, + doublePages: Boolean, + onClickChapterList: () -> Unit, + onClickWebView: () -> Unit, + onClickShare: () -> Unit, + onClickPageLayout: () -> Unit, + onClickShiftPage: () -> Unit, + // SY <-- +) { + // Match with toolbar background color set in ReaderActivity + val backgroundColor = MaterialTheme.colorScheme + .surfaceColorAtElevation(3.dp) + .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) + + Row( + modifier = Modifier + .fillMaxWidth() + .background(backgroundColor) + .padding(8.dp), + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically, + ) { + // SY --> + if (ReaderBottomButton.ViewChapters.isIn(enabledButtons)) { + IconButton(onClick = onClickChapterList) { + Icon( + imageVector = Icons.Outlined.FormatListNumbered, + contentDescription = stringResource(R.string.chapters), + ) + } + } + + if (ReaderBottomButton.WebView.isIn(enabledButtons) && isHttpSource) { + IconButton(onClick = onClickWebView) { + Icon( + imageVector = Icons.Outlined.Public, + contentDescription = stringResource(R.string.action_open_in_web_view), + ) + } + } + + if (ReaderBottomButton.Share.isIn(enabledButtons) && isHttpSource) { + IconButton(onClick = onClickShare) { + Icon( + imageVector = Icons.Outlined.Share, + contentDescription = stringResource(R.string.action_share), + ) + } + } + + if (ReaderBottomButton.ReadingMode.isIn(enabledButtons)) { + IconButton(onClick = onClickReadingMode) { + Icon( + painter = painterResource(readingMode.iconRes), + contentDescription = stringResource(R.string.viewer), + ) + } + } + + val cropBorders = when (readingMode) { + ReadingModeType.WEBTOON -> ReaderBottomButton.CropBordersWebtoon + ReadingModeType.CONTINUOUS_VERTICAL -> ReaderBottomButton.CropBordersContinuesVertical + else -> ReaderBottomButton.CropBordersPager + } + if (cropBorders.isIn(enabledButtons)) { + IconButton(onClick = onClickCropBorder) { + Icon( + painter = painterResource(if (cropEnabled) R.drawable.ic_crop_24dp else R.drawable.ic_crop_off_24dp), + contentDescription = stringResource(R.string.pref_crop_borders), + ) + } + } + + if (ReaderBottomButton.Rotation.isIn(enabledButtons)) { + IconButton(onClick = onClickOrientationMode) { + Icon( + painter = painterResource(orientationMode.iconRes), + contentDescription = stringResource(R.string.pref_rotation_type), + ) + } + } + + if ( + !dualPageSplitEnabled && + ReaderBottomButton.PageLayout.isIn(enabledButtons) && + ReadingModeType.isPagerType(readingMode.prefValue) + ) { + IconButton(onClick = onClickPageLayout) { + Icon( + painter = painterResource(R.drawable.ic_book_open_variant_24dp), + contentDescription = stringResource(R.string.page_layout), + ) + } + } + + if (doublePages) { + IconButton(onClick = onClickShiftPage) { + Icon( + painter = painterResource(R.drawable.ic_page_next_outline_24dp), + contentDescription = stringResource(R.string.shift_double_pages), + ) + } + } + + IconButton(onClick = onClickSettings) { + Icon( + imageVector = Icons.Outlined.Settings, + contentDescription = stringResource(R.string.action_settings), + ) + } + // SY <-- + } +} diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterListDialog.kt b/app/src/main/java/eu/kanade/presentation/reader/ChapterListDialog.kt new file mode 100644 index 000000000..dd31c1514 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/reader/ChapterListDialog.kt @@ -0,0 +1,84 @@ +package eu.kanade.presentation.reader + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import eu.kanade.presentation.components.AdaptiveSheet +import eu.kanade.presentation.manga.components.MangaChapterListItem +import eu.kanade.tachiyomi.data.download.model.Download +import eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterItem +import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel +import eu.kanade.tachiyomi.util.lang.toRelativeString +import exh.metadata.MetadataUtil +import exh.source.isEhBasedManga +import tachiyomi.domain.chapter.model.Chapter +import tachiyomi.domain.library.service.LibraryPreferences +import java.util.Date + +@Composable +fun ChapterListDialog( + onDismissRequest: () -> Unit, + screenModel: ReaderSettingsScreenModel, + chapters: List, + onClickChapter: (Chapter) -> Unit, + onBookmark: (Chapter) -> Unit, +) { + val manga by screenModel.mangaFlow.collectAsState() + val context = LocalContext.current + val state = rememberLazyListState(chapters.indexOfFirst { it.isCurrent }.coerceAtLeast(0)) + + AdaptiveSheet( + onDismissRequest = onDismissRequest, + ) { + LazyColumn( + state = state, + modifier = Modifier.defaultMinSize(minHeight = 200.dp), + contentPadding = PaddingValues(vertical = 16.dp), + ) { + items( + items = chapters, + key = { "chapter-${it.chapter.id}" }, + ) { chapterItem -> + MangaChapterListItem( + title = chapterItem.chapter.name, + date = chapterItem.chapter.dateUpload + .takeIf { it > 0L } + ?.let { + // SY --> + if (manga?.isEhBasedManga() == true) { + MetadataUtil.EX_DATE_FORMAT.format(Date(it)) + } else { + Date(it).toRelativeString(context, chapterItem.dateFormat) + } + // SY <-- + }, + readProgress = null, + scanlator = chapterItem.chapter.scanlator, + sourceName = null, + read = false, + bookmark = chapterItem.chapter.bookmark, + selected = false, + downloadIndicatorEnabled = false, + downloadStateProvider = { Download.State.NOT_DOWNLOADED }, + downloadProgressProvider = { 0 }, + chapterSwipeStartAction = LibraryPreferences.ChapterSwipeAction.ToggleBookmark, + chapterSwipeEndAction = LibraryPreferences.ChapterSwipeAction.ToggleBookmark, + onLongClick = { /*TODO*/ }, + onClick = { onClickChapter(chapterItem.chapter) }, + onDownloadClick = null, + onChapterSwipe = { + onBookmark(chapterItem.chapter) + }, + ) + } + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt b/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt index 39cbee641..ff11dd3c5 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/ChapterNavigator.kt @@ -79,6 +79,15 @@ fun ChapterNavigator( val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr val haptic = LocalHapticFeedback.current + // Match with toolbar background color set in ReaderActivity + val backgroundColor = MaterialTheme.colorScheme + .surfaceColorAtElevation(3.dp) + .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) + val buttonColor = IconButtonDefaults.filledIconButtonColors( + containerColor = backgroundColor, + disabledContainerColor = backgroundColor, + ) + // We explicitly handle direction based on the reader viewer rather than the system direction CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { Row( @@ -87,14 +96,6 @@ fun ChapterNavigator( .padding(horizontal = horizontalPadding), verticalAlignment = Alignment.CenterVertically, ) { - // Match with toolbar background color set in ReaderActivity - val backgroundColor = MaterialTheme.colorScheme - .surfaceColorAtElevation(3.dp) - .copy(alpha = if (isSystemInDarkTheme()) 0.9f else 0.95f) - val buttonColor = IconButtonDefaults.filledIconButtonColors( - containerColor = backgroundColor, - disabledContainerColor = backgroundColor, - ) FilledIconButton( enabled = if (isRtl) enabledNext else enabledPrevious, onClick = if (isRtl) onNextChapter else onPreviousChapter, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt index 0e7a6094f..a0a3d9698 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/EditMangaDialog.kt @@ -31,8 +31,8 @@ import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.system.dpToPx -import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput +import exh.ui.metadata.adapters.MetadataUIUtil.getResourceColor import exh.util.dropBlank import exh.util.trimOrNull import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/merged/EditMergedMangaHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/merged/EditMergedMangaHolder.kt index 2cc65ebfc..949e7de31 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/merged/EditMergedMangaHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/merged/EditMergedMangaHolder.kt @@ -7,7 +7,7 @@ import eu.davidea.viewholders.FlexibleViewHolder import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.EditMergedSettingsItemBinding import eu.kanade.tachiyomi.util.system.dpToPx -import eu.kanade.tachiyomi.util.system.getResourceColor +import exh.ui.metadata.adapters.MetadataUIUtil.getResourceColor import tachiyomi.domain.manga.model.MergedMangaReference import tachiyomi.domain.source.service.SourceManager import uy.kohesive.injekt.Injekt diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 09af9376d..6a5f37500 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -31,6 +31,7 @@ import android.widget.TextView import android.widget.Toast import androidx.activity.viewModels import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator @@ -38,8 +39,11 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState 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.platform.LocalConfiguration import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.core.graphics.ColorUtils @@ -60,6 +64,8 @@ import com.google.android.material.transition.platform.MaterialContainerTransfor import dev.chrisbanes.insetter.applyInsetter import eu.kanade.domain.base.BasePreferences import eu.kanade.domain.manga.model.readingModeType +import eu.kanade.presentation.reader.BottomReaderBar +import eu.kanade.presentation.reader.ChapterListDialog import eu.kanade.presentation.reader.ChapterNavigator import eu.kanade.presentation.reader.OrientationModeSelectDialog import eu.kanade.presentation.reader.PageIndicatorText @@ -71,19 +77,16 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.databinding.ReaderActivityBinding import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.AddToLibraryFirst import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.Error import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.Success -import eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterDialog import eu.kanade.tachiyomi.ui.reader.loader.HttpPageLoader import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.setting.OrientationType -import eu.kanade.tachiyomi.ui.reader.setting.ReaderBottomButton import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences import eu.kanade.tachiyomi.ui.reader.setting.ReaderSettingsScreenModel import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType @@ -100,9 +103,7 @@ import eu.kanade.tachiyomi.util.system.isLTR import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.toShareIntent import eu.kanade.tachiyomi.util.system.toast -import eu.kanade.tachiyomi.util.view.copy import eu.kanade.tachiyomi.util.view.setComposeContent -import eu.kanade.tachiyomi.util.view.setTooltip import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener import exh.source.isEhBasedSource import exh.util.defaultReaderType @@ -126,13 +127,13 @@ import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch import logcat.LogPriority import tachiyomi.core.Constants -import tachiyomi.core.preference.toggle import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.service.SourceManager +import tachiyomi.presentation.core.util.collectAsState import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import kotlin.math.abs @@ -527,8 +528,6 @@ class ReaderActivity : BaseActivity() { if (!readerPreferences.showReadingMode().get()) { menuToggleToast = toast(stringRes) } - - updateCropBordersShortcut() }, ) } @@ -553,6 +552,30 @@ class ReaderActivity : BaseActivity() { hasExtraPage = (state.dialog as? ReaderViewModel.Dialog.PageActions)?.extraPage != null, ) } + is ReaderViewModel.Dialog.ChapterList -> { + var chapters by remember { + mutableStateOf(viewModel.getChapters()) + } + ChapterListDialog( + onDismissRequest = onDismissRequest, + screenModel = settingsScreenModel, + chapters = chapters, + onClickChapter = { + viewModel.loadNewChapterFromDialog(it) + onDismissRequest() + }, + onBookmark = { chapter -> + viewModel.toggleBookmark(chapter.id, !chapter.bookmark) + chapters = chapters.map { + if (it.chapter.id == chapter.id) { + it.copy(chapter = chapter.copy(bookmark = !chapter.bookmark)) + } else { + it + } + } + }, + ) + } null -> {} } } @@ -560,8 +583,19 @@ class ReaderActivity : BaseActivity() { // SY --> val sliderContent: @Composable (Boolean) -> Unit = a@{ isVertical -> val state by viewModel.state.collectAsState() - if (state.viewer == null) return@a + + val forceHorizontalSeekbar by readerPreferences.forceHorizontalSeekbar().collectAsState() + val landscapeVerticalSeekbar by readerPreferences.landscapeVerticalSeekbar().collectAsState() + val configuration = LocalConfiguration.current + val verticalSeekbarLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && landscapeVerticalSeekbar + val verticalSeekbarHorizontal = configuration.orientation == Configuration.ORIENTATION_PORTRAIT + val viewerIsVertical = (state.viewer is WebtoonViewer || state.viewer is VerticalPagerViewer) + val showVerticalSeekbar = !forceHorizontalSeekbar && (verticalSeekbarLandscape || verticalSeekbarHorizontal) && viewerIsVertical + if ((isVertical && !showVerticalSeekbar) || (!isVertical && showVerticalSeekbar)) { + return@a + } + val isRtl = state.viewer is R2LPagerViewer ChapterNavigator( @@ -586,26 +620,103 @@ class ReaderActivity : BaseActivity() { } // Init listeners on bottom menu - binding.readerNavHorz.setComposeContent { - sliderContent(false) - } binding.readerNavVert.setComposeContent { sliderContent(true) } - initBottomShortcuts() + binding.readerMenuBottom.setComposeContent { + val state by viewModel.state.collectAsState() - // SY <-- - updateBottomButtons() + if (state.viewer == null) return@setComposeContent + + val cropBorderPaged by readerPreferences.cropBorders().collectAsState() + val cropBorderWebtoon by readerPreferences.cropBordersWebtoon().collectAsState() + val cropBorderContinuousVertical by readerPreferences.cropBordersContinuousVertical().collectAsState() + val readingMode = viewModel.getMangaReadingMode() + val isPagerType = ReadingModeType.isPagerType(readingMode) + val isWebtoon = ReadingModeType.WEBTOON.prefValue == readingMode + val cropEnabled = if (isPagerType) { + cropBorderPaged + } else if (isWebtoon) { + cropBorderWebtoon + } else { + cropBorderContinuousVertical + } + val readerBottomButtons by readerPreferences.readerBottomButtons().collectAsState() + val dualPageSplitPaged by readerPreferences.dualPageSplitPaged().collectAsState() + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + // SY --> + sliderContent(false) + // SY <-- + + BottomReaderBar( + enabledButtons = readerBottomButtons, + readingMode = ReadingModeType.fromPreference( + viewModel.getMangaReadingMode( + resolveDefault = false, + ), + ), + onClickReadingMode = viewModel::openReadingModeSelectDialog, + orientationMode = OrientationType.fromPreference( + viewModel.getMangaOrientationType( + resolveDefault = false, + ), + ), + onClickOrientationMode = viewModel::openOrientationModeSelectDialog, + cropEnabled = cropEnabled, + onClickCropBorder = { + val enabled = viewModel.toggleCropBorders() + + menuToggleToast?.cancel() + menuToggleToast = toast( + if (enabled) { + R.string.on + } else { + R.string.off + }, + ) + }, + onClickSettings = viewModel::openSettingsDialog, + // SY --> + isHttpSource = remember { + viewModel.getSource() != null + }, + dualPageSplitEnabled = dualPageSplitPaged, + doublePages = state.doublePages, + onClickChapterList = viewModel::openChapterListDialog, + onClickWebView = ::openChapterInWebView, + onClickShare = { + assistUrl?.let { + val intent = it.toUri().toShareIntent(this@ReaderActivity, type = "text/plain") + startActivity(Intent.createChooser(intent, getString(R.string.action_share))) + } + }, + onClickPageLayout = { + if (readerPreferences.pageLayout().get() == PagerConfig.PageLayout.AUTOMATIC) { + (viewModel.state.value.viewer as? PagerViewer)?.config?.let { config -> + config.doublePages = !config.doublePages + reloadChapters(config.doublePages, true) + } + } else { + readerPreferences.pageLayout().set(1 - readerPreferences.pageLayout().get()) + } + }, + onClickShiftPage = ::shiftDoublePages, + // SY <-- + ) + } + } initDropdownMenu() + // SY <-- val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply { elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2) alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light } - binding.toolbarBottom.background = toolbarBackground.copy(this@ReaderActivity) - val toolbarColor = ColorUtils.setAlphaComponent( toolbarBackground.resolvedTintColor, toolbarBackground.alpha, @@ -628,125 +739,6 @@ class ReaderActivity : BaseActivity() { } // EXH --> - fun initBottomShortcuts() { - // Reading mode - with(binding.actionReadingMode) { - setTooltip(R.string.viewer) - - setOnClickListener { - viewModel.openReadingModeSelectDialog() - } - } - - // Crop borders - with(binding.actionCropBorders) { - setTooltip(R.string.pref_crop_borders) - - setOnClickListener { - // SY --> - val mangaViewer = viewModel.getMangaReadingMode() - // SY <-- - val isPagerType = ReadingModeType.isPagerType(mangaViewer) - val enabled = if (isPagerType) { - readerPreferences.cropBorders().toggle() - } else { - // SY --> - if (ReadingModeType.fromPreference(mangaViewer) == ReadingModeType.CONTINUOUS_VERTICAL) { - readerPreferences.cropBordersContinuousVertical().toggle() - } else { - readerPreferences.cropBordersWebtoon().toggle() - } - // SY <-- - } - - menuToggleToast?.cancel() - menuToggleToast = toast( - if (enabled) { - R.string.on - } else { - R.string.off - }, - ) - } - } - updateCropBordersShortcut() - listOf(readerPreferences.cropBorders(), readerPreferences.cropBordersWebtoon() /* SY --> */, readerPreferences.cropBordersContinuousVertical()/* SY <-- */) - .forEach { pref -> - pref.changes() - .onEach { updateCropBordersShortcut() } - .launchIn(lifecycleScope) - } - - // Rotation - with(binding.actionRotation) { - setTooltip(R.string.rotation_type) - - setOnClickListener { - viewModel.openOrientationModeSelectDialog() - } - } - - // Settings sheet - with(binding.actionSettings) { - setTooltip(R.string.action_settings) - - setOnClickListener { - viewModel.openSettingsDialog() - } - } - - // --> EH - with(binding.actionWebView) { - setTooltip(R.string.action_open_in_web_view) - - setOnClickListener { - openChapterInWebView() - } - } - - with(binding.actionChapterList) { - setTooltip(R.string.chapters) - - setOnClickListener { - ReaderChapterDialog(this@ReaderActivity) - } - } - - with(binding.actionShare) { - setTooltip(R.string.action_share) - - setOnClickListener { - assistUrl?.let { - val intent = it.toUri().toShareIntent(this@ReaderActivity, type = "text/plain") - startActivity(Intent.createChooser(intent, getString(R.string.action_share))) - } - } - } - - with(binding.doublePage) { - setTooltip(R.string.page_layout) - - setOnClickListener { - if (readerPreferences.pageLayout().get() == PagerConfig.PageLayout.AUTOMATIC) { - (viewModel.state.value.viewer as? PagerViewer)?.config?.let { config -> - config.doublePages = !config.doublePages - reloadChapters(config.doublePages, true) - } - updateBottomButtons() - } else { - readerPreferences.pageLayout().set(1 - readerPreferences.pageLayout().get()) - } - } - } - with(binding.shiftPageButton) { - setTooltip(R.string.shift_double_pages) - - setOnClickListener { - shiftDoublePages() - } - } - } - fun initDropdownMenu() { binding.expandEhButton.setOnClickListener { val newValue = !viewModel.state.value.ehUtilsVisible @@ -904,36 +896,6 @@ class ReaderActivity : BaseActivity() { return currentPage?.let { viewModel.state.value.viewerChapters?.currChapter?.pages?.getOrNull(it) } } - fun updateBottomButtons() { - val viewer = viewModel.state.value.viewer - val enabledButtons = readerPreferences.readerBottomButtons().get() - with(binding) { - actionReadingMode.isVisible = ReaderBottomButton.ReadingMode.isIn(enabledButtons) - actionRotation.isVisible = - ReaderBottomButton.Rotation.isIn(enabledButtons) - doublePage.isVisible = - viewer is PagerViewer && ReaderBottomButton.PageLayout.isIn(enabledButtons) && !readerPreferences.dualPageSplitPaged().get() - actionCropBorders.isVisible = - if (viewer is PagerViewer) { - ReaderBottomButton.CropBordersPager.isIn(enabledButtons) - } else { - val continuous = (viewer as? WebtoonViewer)?.isContinuous ?: false - if (continuous) { - ReaderBottomButton.CropBordersWebtoon.isIn(enabledButtons) - } else { - ReaderBottomButton.CropBordersContinuesVertical.isIn(enabledButtons) - } - } - actionWebView.isVisible = - ReaderBottomButton.WebView.isIn(enabledButtons) && viewModel.getSource() is HttpSource - actionShare.isVisible = - ReaderBottomButton.Share.isIn(enabledButtons) && viewModel.getSource() is HttpSource - actionChapterList.isVisible = - ReaderBottomButton.ViewChapters.isIn(enabledButtons) - shiftPageButton.isVisible = (viewer as? PagerViewer)?.config?.doublePages ?: false - } - } - fun reloadChapters(doublePages: Boolean, force: Boolean = false) { val viewer = viewModel.state.value.viewer as? PagerViewer ?: return viewer.updateShifting() @@ -941,6 +903,7 @@ class ReaderActivity : BaseActivity() { setDoublePageMode(viewer) } else { viewer.config.doublePages = doublePages + viewModel.setDoublePages(viewer.config.doublePages) } val currentChapter = viewModel.getCurrentChapter() if (doublePages) { @@ -958,6 +921,7 @@ class ReaderActivity : BaseActivity() { private fun setDoublePageMode(viewer: PagerViewer) { val currentOrientation = resources.configuration.orientation viewer.config.doublePages = currentOrientation == Configuration.ORIENTATION_LANDSCAPE + viewModel.setDoublePages(viewer.config.doublePages) } private fun shiftDoublePages() { @@ -973,35 +937,6 @@ class ReaderActivity : BaseActivity() { } // EXH <-- - private fun updateOrientationShortcut(preference: Int) { - val orientation = OrientationType.fromPreference(preference) - binding.actionRotation.setImageResource(orientation.iconRes) - } - - private fun updateCropBordersShortcut() { - val mangaViewer = viewModel.getMangaReadingMode() - val isPagerType = ReadingModeType.isPagerType(mangaViewer) - val enabled = if (isPagerType) { - readerPreferences.cropBorders().get() - } else { - // SY --> - if (ReadingModeType.fromPreference(mangaViewer) == ReadingModeType.CONTINUOUS_VERTICAL) { - readerPreferences.cropBordersContinuousVertical().get() - } else { - readerPreferences.cropBordersWebtoon().get() - } - // SY <-- - } - - binding.actionCropBorders.setImageResource( - if (enabled) { - R.drawable.ic_crop_24dp - } else { - R.drawable.ic_crop_off_24dp - }, - ) - } - /** * Sets the visibility of the menu according to [visible] and with an optional parameter to * [animate] the views. @@ -1088,13 +1023,8 @@ class ReaderActivity : BaseActivity() { */ private fun setManga(manga: Manga) { val prevViewer = viewModel.state.value.viewer - - val viewerMode = ReadingModeType.fromPreference(viewModel.getMangaReadingMode(resolveDefault = false)) - binding.actionReadingMode.setImageResource(viewerMode.iconRes) - val newViewer = ReadingModeType.toViewer(viewModel.getMangaReadingMode(), this) - updateCropBordersShortcut() if (window.sharedElementEnterTransition is MaterialContainerTransform) { // Wait until transition is complete to avoid crash on API 26 window.sharedElementEnterTransition.doOnEnd { @@ -1131,11 +1061,7 @@ class ReaderActivity : BaseActivity() { } // SY --> - - // --> Vertical seekbar hide on landscape - - if ( - !readerPreferences.forceHorizontalSeekbar().get() && + binding.readerNavVert.isVisible = !readerPreferences.forceHorizontalSeekbar().get() && ( ( resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && readerPreferences.landscapeVerticalSeekbar().get() @@ -1143,27 +1069,12 @@ class ReaderActivity : BaseActivity() { resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT ) && (viewModel.state.value.viewer is WebtoonViewer || viewModel.state.value.viewer is VerticalPagerViewer) - ) { - binding.readerNavVert.isVisible = true - binding.readerNavHorz.isVisible = false - } else { - binding.readerNavVert.isVisible = false - binding.readerNavHorz.isVisible = true - } - - // <-- Vertical seekbar hide on landscape - - // --> Left-handed vertical seekbar val params = binding.readerNavVert.layoutParams as RelativeLayout.LayoutParams if (readerPreferences.leftVerticalSeekbar().get() && binding.readerNavVert.isVisible) { params.removeRule(RelativeLayout.ALIGN_PARENT_END) binding.readerNavVert.layoutParams = params } - - // <-- Left-handed vertical seekbar - - updateBottomButtons() // SY <-- supportActionBar?.title = manga.title @@ -1416,7 +1327,6 @@ class ReaderActivity : BaseActivity() { if (newOrientation.flag != requestedOrientation) { requestedOrientation = newOrientation.flag } - updateOrientationShortcut(viewModel.getMangaOrientationType(resolveDefault = false)) } /** @@ -1524,14 +1434,20 @@ class ReaderActivity : BaseActivity() { // SY --> readerPreferences.pageLayout().changes() .drop(1) - .onEach { updateBottomButtons() } + .onEach { + viewModel.setDoublePages( + (viewModel.state.value.viewer as? PagerViewer) + ?.config + ?.doublePages + ?: false, + ) + } .launchIn(lifecycleScope) readerPreferences.dualPageSplitPaged().changes() .drop(1) .onEach { if (viewModel.state.value.viewer !is PagerViewer) return@onEach - updateBottomButtons() reloadChapters( !it && when (readerPreferences.pageLayout().get()) { PagerConfig.PageLayout.DOUBLE_PAGES -> true diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt index bd4ca939a..48ef021f2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.ui.reader import android.app.Application -import android.content.Context import android.net.Uri import androidx.annotation.ColorInt import androidx.compose.runtime.Immutable @@ -71,6 +70,7 @@ import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.runBlocking import logcat.LogPriority +import tachiyomi.core.preference.toggle import tachiyomi.core.util.lang.launchIO import tachiyomi.core.util.lang.launchNonCancellable import tachiyomi.core.util.lang.withIOContext @@ -97,8 +97,6 @@ import tachiyomi.domain.source.service.SourceManager import tachiyomi.source.local.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.text.DecimalFormat -import java.text.DecimalFormatSymbols import java.util.Date /** @@ -333,22 +331,15 @@ class ReaderViewModel( } // SY --> - fun getChapters(context: Context): List { + fun getChapters(): List { val currentChapter = getCurrentChapter() - val decimalFormat = DecimalFormat( - "#.###", - DecimalFormatSymbols() - .apply { decimalSeparator = '.' }, - ) return chapterList.map { ReaderChapterItem( - it.chapter.toDomainChapter()!!, - manga!!, - it.chapter.id == currentChapter?.chapter?.id, - context, - UiPreferences.dateFormat(uiPreferences.dateFormat().get()), - decimalFormat, + chapter = it.chapter.toDomainChapter()!!, + manga = manga!!, + isCurrent = it.chapter.id == currentChapter?.chapter?.id, + dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get()), ) } } @@ -411,9 +402,11 @@ class ReaderViewModel( } } - suspend fun loadNewChapterFromDialog(chapter: Chapter) { - val newChapter = chapterList.firstOrNull { it.chapter.id == chapter.id } ?: return - loadAdjacent(newChapter) + fun loadNewChapterFromDialog(chapter: Chapter) { + viewModelScope.launchIO { + val newChapter = chapterList.firstOrNull { it.chapter.id == chapter.id } ?: return@launchIO + loadAdjacent(newChapter) + } } /** @@ -716,7 +709,7 @@ class ReaderViewModel( viewModelScope.launchNonCancellable { updateChapter.await( ChapterUpdate( - id = chapter.id!!.toLong(), + id = chapterId, bookmark = bookmarked, ), ) @@ -804,6 +797,21 @@ class ReaderViewModel( } } + // SY --> + fun toggleCropBorders(): Boolean { + val readingMode = getMangaReadingMode() + val isPagerType = ReadingModeType.isPagerType(readingMode) + val isWebtoon = ReadingModeType.WEBTOON.prefValue == readingMode + return if (isPagerType) { + readerPreferences.cropBorders().toggle() + } else if (isWebtoon) { + readerPreferences.cropBordersWebtoon().toggle() + } else { + readerPreferences.cropBordersContinuousVertical().toggle() + } + } + // SY <-- + /** * Generate a filename for the given [manga] and [page] */ @@ -834,6 +842,14 @@ class ReaderViewModel( fun setIndexPageToShift(index: Int?) { mutableState.update { it.copy(indexPageToShift = index) } } + + fun openChapterListDialog() { + mutableState.update { it.copy(dialog = Dialog.ChapterList) } + } + + fun setDoublePages(doublePages: Boolean) { + mutableState.update { it.copy(doublePages = doublePages) } + } // SY <-- fun showLoadingDialog() { @@ -1158,6 +1174,7 @@ class ReaderViewModel( val lastShiftDoubleState: Boolean? = null, val indexPageToShift: Int? = null, val indexChapterToShift: Long? = null, + val doublePages: Boolean = false, // SY <-- ) { val totalPages: Int @@ -1169,6 +1186,11 @@ class ReaderViewModel( data object Settings : Dialog data object ReadingModeSelect : Dialog data object OrientationModeSelect : Dialog + + // SY --> + data object ChapterList : Dialog + // SY <-- + data class PageActions(val page: ReaderPage/* SY --> */, val extraPage: ReaderPage? = null /* SY <-- */) : Dialog } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterAdapter.kt deleted file mode 100644 index 95ab11533..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterAdapter.kt +++ /dev/null @@ -1,21 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.chapter - -import eu.davidea.flexibleadapter.FlexibleAdapter -import tachiyomi.domain.chapter.model.Chapter - -class ReaderChapterAdapter( - dialog: OnBookmarkClickListener, -) : FlexibleAdapter(null, dialog, true) { - - /** - * Listener for browse item clicks. - */ - val clickListener: OnBookmarkClickListener = dialog - - /** - * Listener which should be called when user clicks the download icons. - */ - interface OnBookmarkClickListener { - fun bookmarkChapter(chapter: Chapter) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterDialog.kt deleted file mode 100644 index 45f93d119..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterDialog.kt +++ /dev/null @@ -1,80 +0,0 @@ -package eu.kanade.tachiyomi.ui.reader.chapter - -import androidx.appcompat.app.AlertDialog -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.LinearLayoutManager -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.databinding.ReaderChaptersDialogBinding -import eu.kanade.tachiyomi.ui.reader.ReaderActivity -import eu.kanade.tachiyomi.ui.reader.ReaderViewModel -import eu.kanade.tachiyomi.util.system.dpToPx -import kotlinx.coroutines.launch -import tachiyomi.domain.chapter.model.Chapter -import tachiyomi.domain.chapter.service.getChapterSort - -class ReaderChapterDialog(private val activity: ReaderActivity) : ReaderChapterAdapter.OnBookmarkClickListener { - private val binding = ReaderChaptersDialogBinding.inflate(activity.layoutInflater) - - var viewModel: ReaderViewModel = activity.viewModel - var adapter: FlexibleAdapter? = null - var dialog: AlertDialog - - init { - dialog = MaterialAlertDialogBuilder(activity) - .setTitle(R.string.chapters) - .setView(binding.root) - .setNegativeButton(android.R.string.cancel, null) - .setOnDismissListener { destroy() } - .create() - - adapter = ReaderChapterAdapter(this@ReaderChapterDialog) - binding.chapterRecycler.adapter = adapter - - adapter?.mItemClickListener = FlexibleAdapter.OnItemClickListener { _, position -> - val item = adapter?.getItem(position) - if (item != null && item.chapter.id != viewModel.getCurrentChapter()?.chapter?.id) { - dialog.dismiss() - activity.lifecycleScope.launch { - viewModel.loadNewChapterFromDialog(item.chapter) - } - } - true - } - - binding.chapterRecycler.layoutManager = LinearLayoutManager(activity) - activity.lifecycleScope.launch { - refreshList() - } - - dialog.show() - } - - private fun refreshList(scroll: Boolean = true) { - val chapterSort = getChapterSort(viewModel.manga!!) - val chapters = viewModel.getChapters(activity) - .sortedWith { a, b -> - chapterSort(a.chapter, b.chapter) - } - - adapter?.clear() - adapter?.updateDataSet(chapters) - - if (scroll) { - (binding.chapterRecycler.layoutManager as LinearLayoutManager).scrollToPositionWithOffset( - adapter?.getGlobalPositionOf(chapters.find { it.isCurrent }) ?: 0, - (binding.chapterRecycler.height / 2).dpToPx, - ) - } - } - - fun destroy() { - adapter = null - } - - override fun bookmarkChapter(chapter: Chapter) { - viewModel.toggleBookmark(chapter.id, !chapter.bookmark) - refreshList(scroll = false) - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterItem.kt index d410a9410..59a0f1770 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/chapter/ReaderChapterItem.kt @@ -1,133 +1,12 @@ package eu.kanade.tachiyomi.ui.reader.chapter -import android.content.Context -import android.graphics.Typeface -import android.text.SpannableStringBuilder -import android.view.View -import android.widget.ImageView -import androidx.annotation.AttrRes -import androidx.annotation.DrawableRes -import androidx.appcompat.content.res.AppCompatResources -import androidx.recyclerview.widget.RecyclerView -import eu.davidea.flexibleadapter.FlexibleAdapter -import eu.davidea.flexibleadapter.items.AbstractFlexibleItem -import eu.davidea.flexibleadapter.items.IFlexible -import eu.davidea.viewholders.FlexibleViewHolder -import eu.kanade.tachiyomi.R -import eu.kanade.tachiyomi.databinding.ReaderChapterItemBinding -import eu.kanade.tachiyomi.util.system.getResourceColor -import exh.source.isEhBasedManga import tachiyomi.domain.chapter.model.Chapter import tachiyomi.domain.manga.model.Manga import java.text.DateFormat -import java.text.DecimalFormat -import java.util.Date -class ReaderChapterItem(val chapter: Chapter, val manga: Manga, val isCurrent: Boolean, context: Context, val dateFormat: DateFormat, val decimalFormat: DecimalFormat) : - AbstractFlexibleItem() { - - val readColor = context.getResourceColor(R.attr.colorOnSurface, 0.38f) - val unreadColor = context.getResourceColor(R.attr.colorOnSurface) - val bookmarkedColor = context.getResourceColor(R.attr.colorAccent) - - override fun getLayoutRes(): Int { - return R.layout.reader_chapter_item - } - - override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ViewHolder { - return ViewHolder(view, adapter as ReaderChapterAdapter) - } - - override fun bindViewHolder( - adapter: FlexibleAdapter>, - holder: ViewHolder, - position: Int, - payloads: List?, - ) { - holder.bind(this) - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as ReaderChapterItem - - if (chapter.id != other.chapter.id) return false - - return true - } - - override fun hashCode(): Int { - return chapter.id.hashCode() - } - - inner class ViewHolder(view: View, private val adapter: ReaderChapterAdapter) : FlexibleViewHolder(view, adapter) { - val binding = ReaderChapterItemBinding.bind(itemView) - - fun bind(item: ReaderChapterItem) { - val manga = item.manga - val chapter = item.chapter - - binding.chapterTitle.text = when (manga.displayMode) { - Manga.CHAPTER_DISPLAY_NUMBER -> { - val number = item.decimalFormat.format(chapter.chapterNumber.toDouble()) - itemView.context.getString(R.string.display_mode_chapter, number) - } - else -> chapter.name - } - - // Set correct text color - val chapterColor = when { - chapter.read -> item.readColor - chapter.bookmark -> item.bookmarkedColor - else -> item.unreadColor - } - binding.chapterTitle.setTextColor(chapterColor) - binding.chapterScanlator.setTextColor(chapterColor) - - // bookmarkImage.isVisible = item.bookmark - - val descriptions = mutableListOf() - - if (chapter.dateUpload > 0) { - descriptions.add(item.dateFormat.format(Date(chapter.dateUpload))) - } - if (!chapter.scanlator.isNullOrBlank() && !manga.isEhBasedManga()) { - descriptions.add(chapter.scanlator!!) - } - - if (descriptions.isNotEmpty()) { - binding.chapterScanlator.text = descriptions.joinTo(SpannableStringBuilder(), " • ") - } else { - binding.chapterScanlator.text = "" - } - - if (chapter.bookmark) { - binding.bookmarkImage.setVectorCompat(R.drawable.ic_bookmark_24dp, R.attr.colorAccent) - } else { - binding.bookmarkImage.setVectorCompat(R.drawable.ic_bookmark_border_24dp, R.attr.colorOnSurface) - } - - if (item.isCurrent) { - binding.chapterTitle.setTypeface(null, Typeface.BOLD_ITALIC) - binding.chapterScanlator.setTypeface(null, Typeface.BOLD_ITALIC) - } else { - binding.chapterTitle.setTypeface(null, Typeface.NORMAL) - binding.chapterScanlator.setTypeface(null, Typeface.NORMAL) - } - binding.bookmarkLayout.setOnClickListener { - adapter.clickListener.bookmarkChapter(chapter) - } - } - } -} - -fun ImageView.setVectorCompat(@DrawableRes drawable: Int, @AttrRes tint: Int? = null) { - val vector = AppCompatResources.getDrawable(context, drawable) - if (tint != null) { - vector?.mutate() - vector?.setTint(context.getResourceColor(tint)) - } - setImageDrawable(vector) -} +data class ReaderChapterItem( + val chapter: Chapter, + val manga: Manga, + val isCurrent: Boolean, + val dateFormat: DateFormat, +) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index 44012376a..d7be9f9fe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -2,10 +2,8 @@ package eu.kanade.tachiyomi.util.view -import android.content.Context import android.content.res.Resources import android.graphics.Rect -import android.graphics.drawable.Drawable import android.view.Gravity import android.view.Menu import android.view.MenuItem @@ -13,9 +11,7 @@ import android.view.View import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.annotation.MenuRes -import androidx.annotation.StringRes import androidx.appcompat.widget.PopupMenu -import androidx.appcompat.widget.TooltipCompat import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme @@ -24,7 +20,6 @@ import androidx.compose.runtime.CompositionContext import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy -import com.google.android.material.shape.MaterialShapeDrawable import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.tachiyomi.R @@ -60,24 +55,6 @@ fun ComposeView.setComposeContent( } } -/** - * Adds a tooltip shown on long press. - * - * @param stringRes String resource for tooltip. - */ -inline fun View.setTooltip(@StringRes stringRes: Int) { - setTooltip(context.getString(stringRes)) -} - -/** - * Adds a tooltip shown on long press. - * - * @param text Text for tooltip. - */ -inline fun View.setTooltip(text: String) { - TooltipCompat.setTooltipText(this, text) -} - /** * Shows a popup menu on top of this view. * @@ -105,17 +82,6 @@ inline fun View.popupMenu( return popup } -/** - * Returns a deep copy of the provided [Drawable] - */ -inline fun T.copy(context: Context): T? { - return (constantState?.newDrawable()?.mutate() as? T).apply { - if (this is MaterialShapeDrawable) { - initializeElevationOverlay(context) - } - } -} - fun View?.isVisibleOnScreen(): Boolean { if (this == null) { return false diff --git a/app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt b/app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt index 8fe69bf78..8a5f3fd02 100644 --- a/app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt +++ b/app/src/main/java/exh/ui/metadata/adapters/MetadataUIUtil.kt @@ -1,13 +1,19 @@ package exh.ui.metadata.adapters import android.content.Context +import android.graphics.Color import android.widget.TextView +import androidx.annotation.AttrRes +import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.FloatRange import androidx.core.content.ContextCompat +import androidx.core.graphics.alpha +import androidx.core.graphics.blue +import androidx.core.graphics.green +import androidx.core.graphics.red import eu.kanade.tachiyomi.source.R import eu.kanade.tachiyomi.util.system.dpToPx -import eu.kanade.tachiyomi.util.system.getResourceColor import exh.util.SourceTagsUtil import kotlin.math.roundToInt @@ -56,4 +62,24 @@ object MetadataUIUtil { setCompoundDrawables(this, null, null, null) } } + + /** + * Returns the color for the given attribute. + * + * @param resource the attribute. + * @param alphaFactor the alpha number [0,1]. + */ + @ColorInt + fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int { + val typedArray = obtainStyledAttributes(intArrayOf(resource)) + val color = typedArray.getColor(0, 0) + typedArray.recycle() + + if (alphaFactor < 1f) { + val alpha = (color.alpha * alphaFactor).roundToInt() + return Color.argb(alpha, color.red, color.green, color.blue) + } + + return color + } } diff --git a/app/src/main/res/drawable/ic_settings_24dp.xml b/app/src/main/res/drawable/ic_settings_24dp.xml deleted file mode 100644 index 39195ad39..000000000 --- a/app/src/main/res/drawable/ic_settings_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index 7ba27a8e9..edeee713b 100755 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -218,133 +218,15 @@ app:layout_constraintGuide_percent="0.85" app:layout_constraintBottom_toTopOf="@id/reader_menu_bottom"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintStart_toStartOf="parent" />