This commit is contained in:
Koitharu
2024-04-29 19:06:35 +03:00
parent af510beb7b
commit e2d7f2890d
12 changed files with 81 additions and 29 deletions

View File

@@ -18,8 +18,8 @@ import com.google.android.material.R as materialR
class AnimatedPlaceholderDrawable(context: Context) : Drawable(), Animatable, TimeAnimator.TimeListener {
private val colorLow = context.getThemeColor(materialR.attr.colorSurfaceContainerLow)
private val colorHigh = context.getThemeColor(materialR.attr.colorSurfaceContainerHigh)
private val colorLow = context.getThemeColor(materialR.attr.colorBackgroundFloating)
private val colorHigh = context.getThemeColor(materialR.attr.colorSurfaceContainer)
private var currentColor: Int = colorLow
private var alpha: Int = 255
private val interpolator = FastOutSlowInInterpolator()

View File

@@ -22,6 +22,10 @@ import androidx.core.graphics.ColorUtils
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.viewbinding.ViewBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
@@ -131,14 +135,17 @@ abstract class BaseAdaptiveSheet<B : ViewBinding> : AppCompatDialogFragment() {
dialog?.window?.statusBarColor = defaultStatusBarColor
}
fun addSheetCallback(callback: AdaptiveSheetCallback) {
val b = behavior ?: return
fun addSheetCallback(callback: AdaptiveSheetCallback, lifecycleOwner: LifecycleOwner): Boolean {
val b = behavior ?: return false
b.addCallback(callback)
val rootView = dialog?.findViewById<View>(materialR.id.design_bottom_sheet)
?: dialog?.findViewById(materialR.id.coordinator)
?: view
if (rootView != null) {
callback.onStateChanged(rootView, b.state)
}
lifecycleOwner.lifecycle.addObserver(CallbackRemoveObserver(b, callback))
return true
}
protected abstract fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): B
@@ -146,7 +153,8 @@ abstract class BaseAdaptiveSheet<B : ViewBinding> : AppCompatDialogFragment() {
protected open fun onViewBindingCreated(binding: B, savedInstanceState: Bundle?) = Unit
fun startSupportActionMode(callback: ActionMode.Callback): ActionMode? {
val delegate = (dialog as? AppCompatDialog)?.delegate ?: (activity as? AppCompatActivity)?.delegate ?: return null
val delegate =
(dialog as? AppCompatDialog)?.delegate ?: (activity as? AppCompatActivity)?.delegate ?: return null
return delegate.startSupportActionMode(callback)
}
@@ -292,4 +300,16 @@ abstract class BaseAdaptiveSheet<B : ViewBinding> : AppCompatDialogFragment() {
}
}
}
private class CallbackRemoveObserver(
private val behavior: AdaptiveSheetBehavior,
private val callback: AdaptiveSheetCallback,
) : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
owner.lifecycle.removeObserver(this)
behavior.removeCallback(callback)
}
}
}

View File

@@ -93,7 +93,7 @@ fun ImageRequest.Builder.defaultPlaceholders(context: Context): ImageRequest.Bui
val errorColor = ColorUtils.blendARGB(
context.getThemeColor(materialR.attr.colorErrorContainer),
context.getThemeColor(materialR.attr.colorBackgroundFloating),
0.4f,
0.25f,
)
return placeholder(AnimatedPlaceholderDrawable(context))
.fallback(ColorDrawable(context.getThemeColor(materialR.attr.colorSurfaceContainer)))

View File

@@ -97,7 +97,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaTag
import org.koitharu.kotatsu.parsers.util.ellipsize
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
import org.koitharu.kotatsu.reader.ui.ReaderActivity
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
import org.koitharu.kotatsu.search.ui.MangaListActivity
@@ -320,7 +320,7 @@ class DetailsActivity :
override fun onItemClick(item: Bookmark, view: View) {
startActivity(
IntentBuilder(view.context).bookmark(item).incognito(true).build(),
ReaderActivity.IntentBuilder(view.context).bookmark(item).incognito(true).build(),
)
Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show()
}
@@ -535,17 +535,18 @@ class DetailsActivity :
}
private fun onHistoryChanged(info: HistoryInfo, isLoading: Boolean) = with(viewBinding) {
buttonRead.setTitle(if (info.history != null) R.string._continue else R.string.read)
buttonRead.setTitle(if (info.canContinue) R.string._continue else R.string.read)
buttonRead.subtitle = when {
isLoading -> getString(R.string.loading_)
info.isIncognitoMode -> getString(R.string.incognito_mode)
info.isChapterMissing -> getString(R.string.chapter_is_missing)
info.currentChapter >= 0 -> getString(R.string.chapter_d_of_d, info.currentChapter + 1, info.totalChapters)
info.totalChapters == 0 -> getString(R.string.no_chapters)
info.totalChapters == -1 -> getString(R.string.error_occurred)
else -> resources.getQuantityString(R.plurals.chapters, info.totalChapters, info.totalChapters)
}
buttonRead.setProgress(info.history?.percent?.coerceIn(0f, 1f) ?: 0f, true)
buttonDownload?.isEnabled = info.isValid
buttonDownload?.isEnabled = info.isValid && info.canDownload
buttonRead.isEnabled = info.isValid
}
@@ -605,7 +606,7 @@ class DetailsActivity :
.show()
} else {
startActivity(
IntentBuilder(this)
ReaderActivity.IntentBuilder(this)
.manga(manga)
.branch(viewModel.selectedBranchValue)
.incognito(isIncognitoMode)

View File

@@ -84,8 +84,8 @@ class DetailsViewModel @Inject constructor(
) : BaseViewModel() {
private val intent = MangaIntent(savedStateHandle)
private val mangaId = intent.mangaId
private var loadingJob: Job
val mangaId = intent.mangaId
val onActionDone = MutableEventFlow<ReversibleAction>()
val onShowTip = MutableEventFlow<Unit>()
@@ -131,7 +131,7 @@ class DetailsViewModel @Inject constructor(
)
val historyInfo: StateFlow<HistoryInfo> = combine(
manga,
details,
selectedBranch,
history,
interactor.observeIncognitoMode(manga),

View File

@@ -1,6 +1,9 @@
package org.koitharu.kotatsu.details.ui.model
import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.isLocal
import org.koitharu.kotatsu.details.data.MangaDetails
import org.koitharu.kotatsu.parsers.model.Manga
data class HistoryInfo(
@@ -8,26 +11,34 @@ data class HistoryInfo(
val currentChapter: Int,
val history: MangaHistory?,
val isIncognitoMode: Boolean,
val isChapterMissing: Boolean,
val canDownload: Boolean,
) {
val isValid: Boolean
get() = totalChapters >= 0
val canContinue: Boolean
get() = history != null && !isChapterMissing
}
fun HistoryInfo(
manga: Manga?,
manga: MangaDetails?,
branch: String?,
history: MangaHistory?,
isIncognitoMode: Boolean
): HistoryInfo {
val chapters = manga?.getChapters(branch)
val chapters = manga?.chapters?.get(branch)
val currentChapter = if (history != null && !chapters.isNullOrEmpty()) {
chapters.indexOfFirst { it.id == history.chapterId }
} else {
-2
}
return HistoryInfo(
totalChapters = chapters?.size ?: -1,
currentChapter = if (history != null && !chapters.isNullOrEmpty()) {
chapters.indexOfFirst { it.id == history.chapterId }
} else {
-1
},
currentChapter = currentChapter,
history = history,
isIncognitoMode = isIncognitoMode,
isChapterMissing = currentChapter == -1,
canDownload = manga?.isLocal == false,
)
}

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.details.ui.pager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible
@@ -12,6 +13,12 @@ import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior.Companion.STATE_COLLAPSED
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior.Companion.STATE_DRAGGING
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior.Companion.STATE_EXPANDED
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior.Companion.STATE_SETTLING
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetCallback
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
import org.koitharu.kotatsu.core.ui.util.ActionModeListener
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
@@ -28,7 +35,7 @@ import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver
import javax.inject.Inject
@AndroidEntryPoint
class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), ActionModeListener {
class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), ActionModeListener, AdaptiveSheetCallback {
@Inject
lateinit var settings: AppSettings
@@ -58,6 +65,7 @@ class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), Actio
binding.toolbar.addMenuProvider(menuProvider)
actionModeDelegate?.addListener(this, viewLifecycleOwner)
addSheetCallback(this, viewLifecycleOwner)
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.pager, this))
viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.pager, null))
@@ -65,6 +73,14 @@ class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), Actio
viewModel.newChaptersCount.observe(viewLifecycleOwner, ::onNewChaptersChanged)
}
override fun onStateChanged(sheet: View, newState: Int) {
if (newState == STATE_DRAGGING || newState == STATE_SETTLING) {
return
}
val isActionModeStarted = actionModeDelegate?.isActionModeStarted == true
viewBinding?.toolbar?.menuView?.isVisible = newState != STATE_COLLAPSED && !isActionModeStarted
}
override fun onActionModeStarted(mode: ActionMode) {
expandAndLock()
viewBinding?.toolbar?.menuView?.isVisible = false
@@ -72,7 +88,8 @@ class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), Actio
override fun onActionModeFinished(mode: ActionMode) {
unlock()
viewBinding?.toolbar?.menuView?.isVisible = true
val state = behavior?.state ?: STATE_EXPANDED
viewBinding?.toolbar?.menuView?.isVisible = state != STATE_COLLAPSED
}
override fun expandAndLock() {

View File

@@ -75,7 +75,9 @@ class PagesViewModel @Inject constructor(
private suspend fun doInit(state: State) {
chaptersLoader.init(state.details)
val initialChapterId = state.history?.chapterId ?: state.details.allChapters.firstOrNull()?.id ?: return
val initialChapterId = state.history?.chapterId?.takeIf {
chaptersLoader.peekChapter(it) != null
} ?: state.details.allChapters.firstOrNull()?.id ?: return
if (!chaptersLoader.hasPages(initialChapterId)) {
chaptersLoader.loadSingleChapter(initialChapterId)
}

View File

@@ -10,6 +10,7 @@ import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.View.OnTouchListener
import androidx.core.graphics.ColorUtils
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.ImageViewCompat
import androidx.lifecycle.LifecycleOwner
@@ -78,7 +79,7 @@ fun categoryAD(
)
}
binding.imageViewTracker.isVisible = item.category.isTrackingEnabled
binding.imageViewVisible.isVisible = item.category.isVisibleInLibrary
binding.imageViewHidden.isGone = item.category.isVisibleInLibrary
repeat(coverViews.size) { i ->
val cover = item.covers.getOrNull(i)
coverViews[i].newImageRequest(lifecycleOwner, cover?.url)?.run {

View File

@@ -53,7 +53,7 @@ class TagsCatalogSheet : BaseAdaptiveSheet<SheetTagsBinding>(), OnListItemClickL
binding.editSearch.onFocusChangeListener = this
binding.editSearch.setOnEditorActionListener(this)
viewModel.content.observe(viewLifecycleOwner, adapter)
addSheetCallback(this)
addSheetCallback(this, viewLifecycleOwner)
disableFitToContents()
}

View File

@@ -262,7 +262,7 @@
android:id="@+id/chips_tags"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_small"
android:layout_marginTop="@dimen/margin_normal"
android:paddingStart="@dimen/screen_padding"
android:paddingEnd="@dimen/screen_padding"
app:chipSpacingHorizontal="6dp"

View File

@@ -104,13 +104,13 @@
android:layout_marginEnd="4dp"
android:contentDescription="@string/check_for_new_chapters"
app:layout_constraintBottom_toBottomOf="@id/textView_subtitle"
app:layout_constraintEnd_toStartOf="@id/imageView_visible"
app:layout_constraintEnd_toStartOf="@id/imageView_hidden"
app:layout_constraintStart_toEndOf="@id/textView_subtitle"
app:layout_constraintTop_toTopOf="@id/textView_subtitle"
app:srcCompat="@drawable/ic_notification" />
<ImageView
android:id="@+id/imageView_visible"
android:id="@+id/imageView_hidden"
android:layout_width="16dp"
android:layout_height="16dp"
android:contentDescription="@string/show_on_shelf"
@@ -118,7 +118,7 @@
app:layout_constraintEnd_toEndOf="@id/textView_title"
app:layout_constraintStart_toEndOf="@id/imageView_tracker"
app:layout_constraintTop_toTopOf="@id/textView_subtitle"
app:srcCompat="@drawable/ic_eye" />
app:srcCompat="@drawable/ic_eye_off" />
<ImageView
android:id="@+id/imageView_edit"