diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 7a14f2403..91c534ea4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -228,18 +228,18 @@ class DetailsActivity : } } - private fun onHistoryChanged(info: HistoryInfo?) { + private fun onHistoryChanged(info: HistoryInfo) { with(binding.buttonRead) { - if (info?.history != null) { + if (info.history != null) { setText(R.string._continue) - setIconResource(R.drawable.ic_play) + setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play) } else { setText(R.string.read) - setIconResource(R.drawable.ic_read) + setIconResource(if (info.isIncognitoMode) R.drawable.ic_incognito else R.drawable.ic_play) } } val text = when { - info == null -> getString(R.string.loading_) + !info.isValid -> getString(R.string.loading_) info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters) info.totalChapters == 0 -> getString(R.string.no_chapters) else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index c3de6fa13..6d2203632 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -18,7 +18,6 @@ import coil.request.ImageRequest import coil.util.CoilUtils import com.google.android.material.chip.Chip import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import kotlinx.coroutines.launch import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment @@ -27,9 +26,9 @@ import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.base.ui.widgets.ChipsView import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter -import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.databinding.FragmentDetailsBinding import org.koitharu.kotatsu.details.ui.model.ChapterListItem +import org.koitharu.kotatsu.details.ui.model.HistoryInfo import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingItemDecoration import org.koitharu.kotatsu.details.ui.scrobbling.ScrollingInfoAdapter import org.koitharu.kotatsu.history.domain.PROGRESS_NONE @@ -45,8 +44,20 @@ import org.koitharu.kotatsu.scrobbling.domain.model.ScrobblingInfo import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.utils.FileSize -import org.koitharu.kotatsu.utils.ext.* +import org.koitharu.kotatsu.utils.ext.computeSize +import org.koitharu.kotatsu.utils.ext.crossfade +import org.koitharu.kotatsu.utils.ext.drawableTop +import org.koitharu.kotatsu.utils.ext.enqueueWith +import org.koitharu.kotatsu.utils.ext.ifNullOrEmpty +import org.koitharu.kotatsu.utils.ext.measureHeight +import org.koitharu.kotatsu.utils.ext.referer +import org.koitharu.kotatsu.utils.ext.resolveDp +import org.koitharu.kotatsu.utils.ext.scaleUpActivityOptionsOf +import org.koitharu.kotatsu.utils.ext.textAndVisible +import org.koitharu.kotatsu.utils.ext.toFileOrNull +import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.image.CoverSizeResolver +import javax.inject.Inject @AndroidEntryPoint class DetailsFragment : @@ -75,7 +86,7 @@ class DetailsFragment : binding.chipsTags.onChipClickListener = this viewModel.manga.observe(viewLifecycleOwner, ::onMangaUpdated) viewModel.isLoading.observe(viewLifecycleOwner, ::onLoadingStateChanged) - viewModel.readingHistory.observe(viewLifecycleOwner, ::onHistoryChanged) + viewModel.historyInfo.observe(viewLifecycleOwner, ::onHistoryChanged) viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged) viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged) viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged) @@ -123,12 +134,14 @@ class DetailsFragment : drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_finished) } } + MangaState.ONGOING -> { infoLayout.textViewState.apply { textAndVisible = resources.getString(R.string.state_ongoing) drawableTop = ContextCompat.getDrawable(context, R.drawable.ic_state_ongoing) } } + else -> infoLayout.textViewState.isVisible = false } if (manga.source == MangaSource.LOCAL) { @@ -178,8 +191,8 @@ class DetailsFragment : } } - private fun onHistoryChanged(history: MangaHistory?) { - binding.progressView.setPercent(history?.percent ?: PROGRESS_NONE, animate = true) + private fun onHistoryChanged(history: HistoryInfo) { + binding.progressView.setPercent(history.history?.percent ?: PROGRESS_NONE, animate = true) } private fun onLoadingStateChanged(isLoading: Boolean) { @@ -229,6 +242,7 @@ class DetailsFragment : ), ) } + R.id.textView_source -> { startActivity( MangaListActivity.newIntent( @@ -237,6 +251,7 @@ class DetailsFragment : ), ) } + R.id.imageView_cover -> { startActivity( ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }), @@ -249,7 +264,7 @@ class DetailsFragment : override fun onLongClick(v: View): Boolean { when (v.id) { R.id.button_read -> { - if (viewModel.readingHistory.value == null) { + if (viewModel.historyInfo.value?.history == null) { return false } val menu = PopupMenu(v.context, v) @@ -271,12 +286,14 @@ class DetailsFragment : ) true } + else -> false } } menu.show() return true } + else -> return false } } diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 62f340539..b49b1adf8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -13,10 +13,18 @@ import androidx.lifecycle.viewModelScope import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import java.io.IOException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.launch import kotlinx.coroutines.plus import org.koitharu.kotatsu.R @@ -46,6 +54,7 @@ import org.koitharu.kotatsu.utils.asFlowLiveData import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import org.koitharu.kotatsu.utils.ext.printStackTraceDebug import org.koitharu.kotatsu.utils.ext.runCatchingCancellable +import java.io.IOException class DetailsViewModel @AssistedInject constructor( @Assisted intent: MangaIntent, @@ -91,17 +100,18 @@ class DetailsViewModel @AssistedInject constructor( val manga = delegate.manga.filterNotNull().asLiveData(viewModelScope.coroutineContext) val favouriteCategories = favourite.asLiveData(viewModelScope.coroutineContext) val newChaptersCount = newChapters.asLiveData(viewModelScope.coroutineContext) - - @Deprecated("") - val readingHistory = history.asLiveData(viewModelScope.coroutineContext) val isChaptersReversed = chaptersReversed.asLiveData(viewModelScope.coroutineContext) - val historyInfo = combine( + val historyInfo: LiveData = combine( delegate.manga, history, - ) { m, h -> - HistoryInfo(m, h) - }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, null) + settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled }, + ) { m, h, im -> + HistoryInfo(m, h, im) + }.asFlowLiveData( + context = viewModelScope.coroutineContext + Dispatchers.Default, + defaultValue = HistoryInfo(null, null, false), + ) val bookmarks = delegate.manga.flatMapLatest { if (it != null) bookmarksRepository.observeBookmarks(it) else flowOf(emptyList()) diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt index a3fd7f9fa..ae314be62 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/model/HistoryInfo.kt @@ -7,8 +7,12 @@ class HistoryInfo( val totalChapters: Int, val currentChapter: Int, val history: MangaHistory?, + val isIncognitoMode: Boolean, ) { + val isValid: Boolean + get() = totalChapters >= 0 + override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false @@ -18,6 +22,7 @@ class HistoryInfo( if (totalChapters != other.totalChapters) return false if (currentChapter != other.currentChapter) return false if (history != other.history) return false + if (isIncognitoMode != other.isIncognitoMode) return false return true } @@ -26,20 +31,21 @@ class HistoryInfo( var result = totalChapters result = 31 * result + currentChapter result = 31 * result + (history?.hashCode() ?: 0) + result = 31 * result + isIncognitoMode.hashCode() return result } } -@Suppress("FunctionName") -fun HistoryInfo(manga: Manga?, history: MangaHistory?): HistoryInfo? { - val chapters = manga?.chapters ?: return null +fun HistoryInfo(manga: Manga?, history: MangaHistory?, isIncognitoMode: Boolean): HistoryInfo { + val chapters = manga?.chapters return HistoryInfo( - totalChapters = chapters.size, - currentChapter = if (history != null) { + totalChapters = chapters?.size ?: -1, + currentChapter = if (history != null && !chapters.isNullOrEmpty()) { chapters.indexOfFirst { it.id == history.chapterId } } else { -1 }, history = history, + isIncognitoMode = isIncognitoMode, ) } diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt index 7d35e99cf..423b88fbb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainViewModel.kt @@ -12,6 +12,7 @@ import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.github.AppUpdateRepository import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.prefs.observeAsLiveData import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga @@ -34,9 +35,12 @@ class MainViewModel @Inject constructor( val onOpenReader = SingleLiveEvent() - val isResumeEnabled = historyRepository - .observeHasItems() - .asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) + val isResumeEnabled = combine( + historyRepository.observeHasItems(), + settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled }, + ) { hasItems, incognito -> + hasItems && !incognito + }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, false) val isFeedAvailable = settings.observeAsLiveData( context = viewModelScope.coroutineContext + Dispatchers.Default,