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
This commit is contained in:
parent
eb8685fa7e
commit
ebb690cbe7
@ -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<String>,
|
||||||
|
// 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 <--
|
||||||
|
}
|
||||||
|
}
|
@ -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<ReaderChapterItem>,
|
||||||
|
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)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -79,6 +79,15 @@ fun ChapterNavigator(
|
|||||||
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
|
val layoutDirection = if (isRtl) LayoutDirection.Rtl else LayoutDirection.Ltr
|
||||||
val haptic = LocalHapticFeedback.current
|
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
|
// We explicitly handle direction based on the reader viewer rather than the system direction
|
||||||
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) {
|
||||||
Row(
|
Row(
|
||||||
@ -87,14 +96,6 @@ fun ChapterNavigator(
|
|||||||
.padding(horizontal = horizontalPadding),
|
.padding(horizontal = horizontalPadding),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
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(
|
FilledIconButton(
|
||||||
enabled = if (isRtl) enabledNext else enabledPrevious,
|
enabled = if (isRtl) enabledNext else enabledPrevious,
|
||||||
onClick = if (isRtl) onNextChapter else onPreviousChapter,
|
onClick = if (isRtl) onNextChapter else onPreviousChapter,
|
||||||
|
@ -31,8 +31,8 @@ import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.util.lang.chop
|
import eu.kanade.tachiyomi.util.lang.chop
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
|
||||||
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
|
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
|
||||||
|
import exh.ui.metadata.adapters.MetadataUIUtil.getResourceColor
|
||||||
import exh.util.dropBlank
|
import exh.util.dropBlank
|
||||||
import exh.util.trimOrNull
|
import exh.util.trimOrNull
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -7,7 +7,7 @@ import eu.davidea.viewholders.FlexibleViewHolder
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.databinding.EditMergedSettingsItemBinding
|
import eu.kanade.tachiyomi.databinding.EditMergedSettingsItemBinding
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
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.manga.model.MergedMangaReference
|
||||||
import tachiyomi.domain.source.service.SourceManager
|
import tachiyomi.domain.source.service.SourceManager
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
|
@ -31,6 +31,7 @@ import android.widget.TextView
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
@ -38,8 +39,11 @@ import androidx.compose.material3.Text
|
|||||||
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
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.graphics.ColorUtils
|
import androidx.core.graphics.ColorUtils
|
||||||
@ -60,6 +64,8 @@ import com.google.android.material.transition.platform.MaterialContainerTransfor
|
|||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.manga.model.readingModeType
|
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.ChapterNavigator
|
||||||
import eu.kanade.presentation.reader.OrientationModeSelectDialog
|
import eu.kanade.presentation.reader.OrientationModeSelectDialog
|
||||||
import eu.kanade.presentation.reader.PageIndicatorText
|
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.data.notification.Notifications
|
||||||
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
|
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
|
||||||
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.ui.base.activity.BaseActivity
|
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.AddToLibraryFirst
|
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.Error
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderViewModel.SetAsCoverResult.Success
|
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.loader.HttpPageLoader
|
||||||
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
|
||||||
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.ReaderBottomButton
|
|
||||||
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.ReaderSettingsScreenModel
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
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.isNightMode
|
||||||
import eu.kanade.tachiyomi.util.system.toShareIntent
|
import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
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.setComposeContent
|
||||||
import eu.kanade.tachiyomi.util.view.setTooltip
|
|
||||||
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
|
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
|
||||||
import exh.source.isEhBasedSource
|
import exh.source.isEhBasedSource
|
||||||
import exh.util.defaultReaderType
|
import exh.util.defaultReaderType
|
||||||
@ -126,13 +127,13 @@ import kotlinx.coroutines.flow.sample
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.Constants
|
import tachiyomi.core.Constants
|
||||||
import tachiyomi.core.preference.toggle
|
|
||||||
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.withUIContext
|
import tachiyomi.core.util.lang.withUIContext
|
||||||
import tachiyomi.core.util.system.logcat
|
import tachiyomi.core.util.system.logcat
|
||||||
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.presentation.core.util.collectAsState
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@ -527,8 +528,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
if (!readerPreferences.showReadingMode().get()) {
|
if (!readerPreferences.showReadingMode().get()) {
|
||||||
menuToggleToast = toast(stringRes)
|
menuToggleToast = toast(stringRes)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCropBordersShortcut()
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -553,6 +552,30 @@ class ReaderActivity : BaseActivity() {
|
|||||||
hasExtraPage = (state.dialog as? ReaderViewModel.Dialog.PageActions)?.extraPage != null,
|
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 -> {}
|
null -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,8 +583,19 @@ class ReaderActivity : BaseActivity() {
|
|||||||
// SY -->
|
// SY -->
|
||||||
val sliderContent: @Composable (Boolean) -> Unit = a@{ isVertical ->
|
val sliderContent: @Composable (Boolean) -> Unit = a@{ isVertical ->
|
||||||
val state by viewModel.state.collectAsState()
|
val state by viewModel.state.collectAsState()
|
||||||
|
|
||||||
if (state.viewer == null) return@a
|
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
|
val isRtl = state.viewer is R2LPagerViewer
|
||||||
|
|
||||||
ChapterNavigator(
|
ChapterNavigator(
|
||||||
@ -586,26 +620,103 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init listeners on bottom menu
|
// Init listeners on bottom menu
|
||||||
binding.readerNavHorz.setComposeContent {
|
|
||||||
sliderContent(false)
|
|
||||||
}
|
|
||||||
binding.readerNavVert.setComposeContent {
|
binding.readerNavVert.setComposeContent {
|
||||||
sliderContent(true)
|
sliderContent(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
initBottomShortcuts()
|
binding.readerMenuBottom.setComposeContent {
|
||||||
|
val state by viewModel.state.collectAsState()
|
||||||
|
|
||||||
// SY <--
|
if (state.viewer == null) return@setComposeContent
|
||||||
updateBottomButtons()
|
|
||||||
|
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()
|
initDropdownMenu()
|
||||||
|
// SY <--
|
||||||
|
|
||||||
val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply {
|
val toolbarBackground = (binding.toolbar.background as MaterialShapeDrawable).apply {
|
||||||
elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2)
|
elevation = resources.getDimension(R.dimen.m3_sys_elevation_level2)
|
||||||
alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light
|
alpha = if (isNightMode()) 230 else 242 // 90% dark 95% light
|
||||||
}
|
}
|
||||||
binding.toolbarBottom.background = toolbarBackground.copy(this@ReaderActivity)
|
|
||||||
|
|
||||||
val toolbarColor = ColorUtils.setAlphaComponent(
|
val toolbarColor = ColorUtils.setAlphaComponent(
|
||||||
toolbarBackground.resolvedTintColor,
|
toolbarBackground.resolvedTintColor,
|
||||||
toolbarBackground.alpha,
|
toolbarBackground.alpha,
|
||||||
@ -628,125 +739,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXH -->
|
// 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() {
|
fun initDropdownMenu() {
|
||||||
binding.expandEhButton.setOnClickListener {
|
binding.expandEhButton.setOnClickListener {
|
||||||
val newValue = !viewModel.state.value.ehUtilsVisible
|
val newValue = !viewModel.state.value.ehUtilsVisible
|
||||||
@ -904,36 +896,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
return currentPage?.let { viewModel.state.value.viewerChapters?.currChapter?.pages?.getOrNull(it) }
|
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) {
|
fun reloadChapters(doublePages: Boolean, force: Boolean = false) {
|
||||||
val viewer = viewModel.state.value.viewer as? PagerViewer ?: return
|
val viewer = viewModel.state.value.viewer as? PagerViewer ?: return
|
||||||
viewer.updateShifting()
|
viewer.updateShifting()
|
||||||
@ -941,6 +903,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
setDoublePageMode(viewer)
|
setDoublePageMode(viewer)
|
||||||
} else {
|
} else {
|
||||||
viewer.config.doublePages = doublePages
|
viewer.config.doublePages = doublePages
|
||||||
|
viewModel.setDoublePages(viewer.config.doublePages)
|
||||||
}
|
}
|
||||||
val currentChapter = viewModel.getCurrentChapter()
|
val currentChapter = viewModel.getCurrentChapter()
|
||||||
if (doublePages) {
|
if (doublePages) {
|
||||||
@ -958,6 +921,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
private fun setDoublePageMode(viewer: PagerViewer) {
|
private fun setDoublePageMode(viewer: PagerViewer) {
|
||||||
val currentOrientation = resources.configuration.orientation
|
val currentOrientation = resources.configuration.orientation
|
||||||
viewer.config.doublePages = currentOrientation == Configuration.ORIENTATION_LANDSCAPE
|
viewer.config.doublePages = currentOrientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
viewModel.setDoublePages(viewer.config.doublePages)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shiftDoublePages() {
|
private fun shiftDoublePages() {
|
||||||
@ -973,35 +937,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
// EXH <--
|
// 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
|
* Sets the visibility of the menu according to [visible] and with an optional parameter to
|
||||||
* [animate] the views.
|
* [animate] the views.
|
||||||
@ -1088,13 +1023,8 @@ class ReaderActivity : BaseActivity() {
|
|||||||
*/
|
*/
|
||||||
private fun setManga(manga: Manga) {
|
private fun setManga(manga: Manga) {
|
||||||
val prevViewer = viewModel.state.value.viewer
|
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)
|
val newViewer = ReadingModeType.toViewer(viewModel.getMangaReadingMode(), this)
|
||||||
|
|
||||||
updateCropBordersShortcut()
|
|
||||||
if (window.sharedElementEnterTransition is MaterialContainerTransform) {
|
if (window.sharedElementEnterTransition is MaterialContainerTransform) {
|
||||||
// Wait until transition is complete to avoid crash on API 26
|
// Wait until transition is complete to avoid crash on API 26
|
||||||
window.sharedElementEnterTransition.doOnEnd {
|
window.sharedElementEnterTransition.doOnEnd {
|
||||||
@ -1131,11 +1061,7 @@ class ReaderActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
|
binding.readerNavVert.isVisible = !readerPreferences.forceHorizontalSeekbar().get() &&
|
||||||
// --> Vertical seekbar hide on landscape
|
|
||||||
|
|
||||||
if (
|
|
||||||
!readerPreferences.forceHorizontalSeekbar().get() &&
|
|
||||||
(
|
(
|
||||||
(
|
(
|
||||||
resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && readerPreferences.landscapeVerticalSeekbar().get()
|
resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE && readerPreferences.landscapeVerticalSeekbar().get()
|
||||||
@ -1143,27 +1069,12 @@ class ReaderActivity : BaseActivity() {
|
|||||||
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
) &&
|
) &&
|
||||||
(viewModel.state.value.viewer is WebtoonViewer || viewModel.state.value.viewer is VerticalPagerViewer)
|
(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
|
val params = binding.readerNavVert.layoutParams as RelativeLayout.LayoutParams
|
||||||
if (readerPreferences.leftVerticalSeekbar().get() && binding.readerNavVert.isVisible) {
|
if (readerPreferences.leftVerticalSeekbar().get() && binding.readerNavVert.isVisible) {
|
||||||
params.removeRule(RelativeLayout.ALIGN_PARENT_END)
|
params.removeRule(RelativeLayout.ALIGN_PARENT_END)
|
||||||
binding.readerNavVert.layoutParams = params
|
binding.readerNavVert.layoutParams = params
|
||||||
}
|
}
|
||||||
|
|
||||||
// <-- Left-handed vertical seekbar
|
|
||||||
|
|
||||||
updateBottomButtons()
|
|
||||||
// SY <--
|
// SY <--
|
||||||
supportActionBar?.title = manga.title
|
supportActionBar?.title = manga.title
|
||||||
|
|
||||||
@ -1416,7 +1327,6 @@ class ReaderActivity : BaseActivity() {
|
|||||||
if (newOrientation.flag != requestedOrientation) {
|
if (newOrientation.flag != requestedOrientation) {
|
||||||
requestedOrientation = newOrientation.flag
|
requestedOrientation = newOrientation.flag
|
||||||
}
|
}
|
||||||
updateOrientationShortcut(viewModel.getMangaOrientationType(resolveDefault = false))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1524,14 +1434,20 @@ class ReaderActivity : BaseActivity() {
|
|||||||
// SY -->
|
// SY -->
|
||||||
readerPreferences.pageLayout().changes()
|
readerPreferences.pageLayout().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach { updateBottomButtons() }
|
.onEach {
|
||||||
|
viewModel.setDoublePages(
|
||||||
|
(viewModel.state.value.viewer as? PagerViewer)
|
||||||
|
?.config
|
||||||
|
?.doublePages
|
||||||
|
?: false,
|
||||||
|
)
|
||||||
|
}
|
||||||
.launchIn(lifecycleScope)
|
.launchIn(lifecycleScope)
|
||||||
|
|
||||||
readerPreferences.dualPageSplitPaged().changes()
|
readerPreferences.dualPageSplitPaged().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach {
|
.onEach {
|
||||||
if (viewModel.state.value.viewer !is PagerViewer) return@onEach
|
if (viewModel.state.value.viewer !is PagerViewer) return@onEach
|
||||||
updateBottomButtons()
|
|
||||||
reloadChapters(
|
reloadChapters(
|
||||||
!it && when (readerPreferences.pageLayout().get()) {
|
!it && when (readerPreferences.pageLayout().get()) {
|
||||||
PagerConfig.PageLayout.DOUBLE_PAGES -> true
|
PagerConfig.PageLayout.DOUBLE_PAGES -> true
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader
|
package eu.kanade.tachiyomi.ui.reader
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
@ -71,6 +70,7 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
|||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import logcat.LogPriority
|
import logcat.LogPriority
|
||||||
|
import tachiyomi.core.preference.toggle
|
||||||
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
|
||||||
@ -97,8 +97,6 @@ import tachiyomi.domain.source.service.SourceManager
|
|||||||
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
|
||||||
import java.text.DecimalFormat
|
|
||||||
import java.text.DecimalFormatSymbols
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -333,22 +331,15 @@ class ReaderViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
fun getChapters(context: Context): List<ReaderChapterItem> {
|
fun getChapters(): List<ReaderChapterItem> {
|
||||||
val currentChapter = getCurrentChapter()
|
val currentChapter = getCurrentChapter()
|
||||||
val decimalFormat = DecimalFormat(
|
|
||||||
"#.###",
|
|
||||||
DecimalFormatSymbols()
|
|
||||||
.apply { decimalSeparator = '.' },
|
|
||||||
)
|
|
||||||
|
|
||||||
return chapterList.map {
|
return chapterList.map {
|
||||||
ReaderChapterItem(
|
ReaderChapterItem(
|
||||||
it.chapter.toDomainChapter()!!,
|
chapter = it.chapter.toDomainChapter()!!,
|
||||||
manga!!,
|
manga = manga!!,
|
||||||
it.chapter.id == currentChapter?.chapter?.id,
|
isCurrent = it.chapter.id == currentChapter?.chapter?.id,
|
||||||
context,
|
dateFormat = UiPreferences.dateFormat(uiPreferences.dateFormat().get()),
|
||||||
UiPreferences.dateFormat(uiPreferences.dateFormat().get()),
|
|
||||||
decimalFormat,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,9 +402,11 @@ class ReaderViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadNewChapterFromDialog(chapter: Chapter) {
|
fun loadNewChapterFromDialog(chapter: Chapter) {
|
||||||
val newChapter = chapterList.firstOrNull { it.chapter.id == chapter.id } ?: return
|
viewModelScope.launchIO {
|
||||||
loadAdjacent(newChapter)
|
val newChapter = chapterList.firstOrNull { it.chapter.id == chapter.id } ?: return@launchIO
|
||||||
|
loadAdjacent(newChapter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -716,7 +709,7 @@ class ReaderViewModel(
|
|||||||
viewModelScope.launchNonCancellable {
|
viewModelScope.launchNonCancellable {
|
||||||
updateChapter.await(
|
updateChapter.await(
|
||||||
ChapterUpdate(
|
ChapterUpdate(
|
||||||
id = chapter.id!!.toLong(),
|
id = chapterId,
|
||||||
bookmark = bookmarked,
|
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]
|
* Generate a filename for the given [manga] and [page]
|
||||||
*/
|
*/
|
||||||
@ -834,6 +842,14 @@ class ReaderViewModel(
|
|||||||
fun setIndexPageToShift(index: Int?) {
|
fun setIndexPageToShift(index: Int?) {
|
||||||
mutableState.update { it.copy(indexPageToShift = index) }
|
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 <--
|
// SY <--
|
||||||
|
|
||||||
fun showLoadingDialog() {
|
fun showLoadingDialog() {
|
||||||
@ -1158,6 +1174,7 @@ class ReaderViewModel(
|
|||||||
val lastShiftDoubleState: Boolean? = null,
|
val lastShiftDoubleState: Boolean? = null,
|
||||||
val indexPageToShift: Int? = null,
|
val indexPageToShift: Int? = null,
|
||||||
val indexChapterToShift: Long? = null,
|
val indexChapterToShift: Long? = null,
|
||||||
|
val doublePages: Boolean = false,
|
||||||
// SY <--
|
// SY <--
|
||||||
) {
|
) {
|
||||||
val totalPages: Int
|
val totalPages: Int
|
||||||
@ -1169,6 +1186,11 @@ class ReaderViewModel(
|
|||||||
data object Settings : Dialog
|
data object Settings : Dialog
|
||||||
data object ReadingModeSelect : Dialog
|
data object ReadingModeSelect : Dialog
|
||||||
data object OrientationModeSelect : Dialog
|
data object OrientationModeSelect : Dialog
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
data object ChapterList : Dialog
|
||||||
|
// SY <--
|
||||||
|
|
||||||
data class PageActions(val page: ReaderPage/* SY --> */, val extraPage: ReaderPage? = null /* SY <-- */) : Dialog
|
data class PageActions(val page: ReaderPage/* SY --> */, val extraPage: ReaderPage? = null /* SY <-- */) : Dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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<ReaderChapterItem>(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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<ReaderChapterItem>? = 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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,133 +1,12 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.chapter
|
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.chapter.model.Chapter
|
||||||
import tachiyomi.domain.manga.model.Manga
|
import tachiyomi.domain.manga.model.Manga
|
||||||
import java.text.DateFormat
|
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) :
|
data class ReaderChapterItem(
|
||||||
AbstractFlexibleItem<ReaderChapterItem.ViewHolder>() {
|
val chapter: Chapter,
|
||||||
|
val manga: Manga,
|
||||||
val readColor = context.getResourceColor(R.attr.colorOnSurface, 0.38f)
|
val isCurrent: Boolean,
|
||||||
val unreadColor = context.getResourceColor(R.attr.colorOnSurface)
|
val dateFormat: DateFormat,
|
||||||
val bookmarkedColor = context.getResourceColor(R.attr.colorAccent)
|
)
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
|
||||||
return R.layout.reader_chapter_item
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): ViewHolder {
|
|
||||||
return ViewHolder(view, adapter as ReaderChapterAdapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun bindViewHolder(
|
|
||||||
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>,
|
|
||||||
holder: ViewHolder,
|
|
||||||
position: Int,
|
|
||||||
payloads: List<Any?>?,
|
|
||||||
) {
|
|
||||||
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<CharSequence>()
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
@ -2,10 +2,8 @@
|
|||||||
|
|
||||||
package eu.kanade.tachiyomi.util.view
|
package eu.kanade.tachiyomi.util.view
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
@ -13,9 +11,7 @@ import android.view.View
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.annotation.MenuRes
|
import androidx.annotation.MenuRes
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.appcompat.widget.TooltipCompat
|
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@ -24,7 +20,6 @@ import androidx.compose.runtime.CompositionContext
|
|||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||||
import com.google.android.material.shape.MaterialShapeDrawable
|
|
||||||
import eu.kanade.presentation.theme.TachiyomiTheme
|
import eu.kanade.presentation.theme.TachiyomiTheme
|
||||||
import eu.kanade.tachiyomi.R
|
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.
|
* Shows a popup menu on top of this view.
|
||||||
*
|
*
|
||||||
@ -105,17 +82,6 @@ inline fun View.popupMenu(
|
|||||||
return popup
|
return popup
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a deep copy of the provided [Drawable]
|
|
||||||
*/
|
|
||||||
inline fun <reified T : Drawable> T.copy(context: Context): T? {
|
|
||||||
return (constantState?.newDrawable()?.mutate() as? T).apply {
|
|
||||||
if (this is MaterialShapeDrawable) {
|
|
||||||
initializeElevationOverlay(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun View?.isVisibleOnScreen(): Boolean {
|
fun View?.isVisibleOnScreen(): Boolean {
|
||||||
if (this == null) {
|
if (this == null) {
|
||||||
return false
|
return false
|
||||||
|
@ -1,13 +1,19 @@
|
|||||||
package exh.ui.metadata.adapters
|
package exh.ui.metadata.adapters
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.FloatRange
|
import androidx.annotation.FloatRange
|
||||||
import androidx.core.content.ContextCompat
|
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.source.R
|
||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
|
||||||
import exh.util.SourceTagsUtil
|
import exh.util.SourceTagsUtil
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -56,4 +62,24 @@ object MetadataUIUtil {
|
|||||||
setCompoundDrawables(this, null, null, null)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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="#000"
|
|
||||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z" />
|
|
||||||
</vector>
|
|
@ -218,133 +218,15 @@
|
|||||||
app:layout_constraintGuide_percent="0.85"
|
app:layout_constraintGuide_percent="0.85"
|
||||||
app:layout_constraintBottom_toTopOf="@id/reader_menu_bottom"/>
|
app:layout_constraintBottom_toTopOf="@id/reader_menu_bottom"/>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.compose.ui.platform.ComposeView
|
||||||
android:id="@+id/reader_menu_bottom"
|
android:id="@+id/reader_menu_bottom"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
android:layout_gravity="bottom"
|
||||||
android:orientation="vertical"
|
android:minHeight="52dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<androidx.compose.ui.platform.ComposeView
|
|
||||||
android:id="@+id/reader_nav_horz"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layoutDirection="ltr" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/toolbar_bottom"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:clickable="true"
|
|
||||||
tools:ignore="KeyboardInaccessibleWidget">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_chapter_list"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/chapters"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
app:srcCompat="@drawable/ic_format_list_numbered_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_web_view"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/action_open_in_web_view"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_webview_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_share"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/action_share"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_share_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_reading_mode"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/viewer"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_reader_default_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_crop_borders"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/pref_crop_borders"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_crop_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_rotation"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/pref_rotation_type"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_screen_rotation_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/double_page"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/page_layout"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_book_open_variant_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/shift_page_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/shift_double_pages"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_page_next_outline_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/action_settings"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/action_settings"
|
|
||||||
android:padding="@dimen/screen_edge_margin"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:srcCompat="@drawable/ic_settings_24dp"
|
|
||||||
app:tint="?attr/colorOnSurface" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user