Information toast in reader
This commit is contained in:
@@ -86,7 +86,7 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
|
|||||||
viewModel.onError.observe(this, this::onError)
|
viewModel.onError.observe(this, this::onError)
|
||||||
viewModel.readerMode.observe(this, this::onInitReader)
|
viewModel.readerMode.observe(this, this::onInitReader)
|
||||||
viewModel.onPageSaved.observe(this, this::onPageSaved)
|
viewModel.onPageSaved.observe(this, this::onPageSaved)
|
||||||
viewModel.uiState.observe(this, this::onUiStateChanged)
|
viewModel.uiState.observeWithPrevious(this, this::onUiStateChanged)
|
||||||
viewModel.isLoading.observe(this, this::onLoadingStateChanged)
|
viewModel.isLoading.observe(this, this::onLoadingStateChanged)
|
||||||
viewModel.content.observe(this) {
|
viewModel.content.observe(this) {
|
||||||
onLoadingStateChanged(viewModel.isLoading.value == true)
|
onLoadingStateChanged(viewModel.isLoading.value == true)
|
||||||
@@ -204,7 +204,11 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
|
|||||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||||
val hasPages = !viewModel.content.value?.pages.isNullOrEmpty()
|
val hasPages = !viewModel.content.value?.pages.isNullOrEmpty()
|
||||||
binding.layoutLoading.isVisible = isLoading && !hasPages
|
binding.layoutLoading.isVisible = isLoading && !hasPages
|
||||||
binding.progressBarBottom.isVisible = isLoading && hasPages
|
if (isLoading && hasPages) {
|
||||||
|
binding.toastView.show(R.string.loading_, true)
|
||||||
|
} else {
|
||||||
|
binding.toastView.hide()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onError(e: Throwable) {
|
private fun onError(e: Throwable) {
|
||||||
@@ -336,19 +340,25 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
|
|||||||
setUiIsVisible(!binding.appbarTop.isVisible)
|
setUiIsVisible(!binding.appbarTop.isVisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onUiStateChanged(uiState: ReaderUiState) {
|
private fun onUiStateChanged(uiState: ReaderUiState, previous: ReaderUiState?) {
|
||||||
title = uiState.chapterName ?: uiState.mangaName ?: getString(R.string.loading_)
|
title = uiState.chapterName ?: uiState.mangaName ?: getString(R.string.loading_)
|
||||||
supportActionBar?.subtitle = if (uiState.chapterNumber in 1..uiState.chaptersTotal) {
|
supportActionBar?.subtitle = if (uiState.chapterNumber in 1..uiState.chaptersTotal) {
|
||||||
getString(R.string.chapter_d_of_d, uiState.chapterNumber, uiState.chaptersTotal)
|
getString(R.string.chapter_d_of_d, uiState.chapterNumber, uiState.chaptersTotal)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
if (previous?.chapterName != null && uiState.chapterName != previous.chapterName) {
|
||||||
|
if (!uiState.chapterName.isNullOrEmpty()) {
|
||||||
|
binding.toastView.showTemporary(uiState.chapterName, TOAST_DURATION)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val ACTION_MANGA_READ = "${BuildConfig.APPLICATION_ID}.action.READ_MANGA"
|
const val ACTION_MANGA_READ = "${BuildConfig.APPLICATION_ID}.action.READ_MANGA"
|
||||||
private const val EXTRA_STATE = "state"
|
private const val EXTRA_STATE = "state"
|
||||||
|
private const val TOAST_DURATION = 1500L
|
||||||
|
|
||||||
fun newIntent(context: Context, manga: Manga, state: ReaderState?): Intent {
|
fun newIntent(context: Context, manga: Manga, state: ReaderState?): Intent {
|
||||||
return Intent(context, ReaderActivity::class.java)
|
return Intent(context, ReaderActivity::class.java)
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.koitharu.kotatsu.reader.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||||
|
import com.google.android.material.textview.MaterialTextView
|
||||||
|
import org.koitharu.kotatsu.utils.anim.Duration
|
||||||
|
import org.koitharu.kotatsu.utils.anim.Motion
|
||||||
|
import org.koitharu.kotatsu.utils.ext.hideAnimated
|
||||||
|
import org.koitharu.kotatsu.utils.ext.showAnimated
|
||||||
|
|
||||||
|
class ReaderToastView @JvmOverloads constructor(
|
||||||
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||||
|
) : MaterialTextView(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private var hideRunnable = Runnable {
|
||||||
|
hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(message: CharSequence, isLoading: Boolean) {
|
||||||
|
removeCallbacks(hideRunnable)
|
||||||
|
text = message
|
||||||
|
this.showAnimated(Motion.Toast, Duration.SHORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show(@StringRes messageId: Int, isLoading: Boolean) {
|
||||||
|
show(context.getString(messageId), isLoading)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showTemporary(message: CharSequence, duration: Long) {
|
||||||
|
show(message, false)
|
||||||
|
postDelayed(hideRunnable, duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide() {
|
||||||
|
removeCallbacks(hideRunnable)
|
||||||
|
this.hideAnimated(Motion.Toast, Duration.SHORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
removeCallbacks(hideRunnable)
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME use it as compound drawable
|
||||||
|
private fun createProgressDrawable(): CircularProgressDrawable {
|
||||||
|
val drawable = CircularProgressDrawable(context)
|
||||||
|
drawable.setStyle(CircularProgressDrawable.DEFAULT)
|
||||||
|
drawable.arrowEnabled = false
|
||||||
|
drawable.setColorSchemeColors(Color.WHITE)
|
||||||
|
drawable.centerRadius = lineHeight / 3f
|
||||||
|
return drawable
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@ package org.koitharu.kotatsu.utils.anim
|
|||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewPropertyAnimator
|
import android.view.ViewPropertyAnimator
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator
|
import android.view.animation.AccelerateInterpolator
|
||||||
|
import android.view.animation.DecelerateInterpolator
|
||||||
import org.koitharu.kotatsu.utils.ext.measureHeight
|
import org.koitharu.kotatsu.utils.ext.measureHeight
|
||||||
|
|
||||||
sealed class Motion {
|
sealed class Motion {
|
||||||
@@ -69,27 +70,25 @@ sealed class Motion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object CheckEffect : Motion() {
|
object Toast : Motion() {
|
||||||
override fun reset(v: View) {
|
override fun reset(v: View) {
|
||||||
v.scaleX = 1f
|
v.alpha = 1f
|
||||||
v.scaleY = 1f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hideView(v: View) {
|
override fun hideView(v: View) {
|
||||||
v.scaleX = 0f
|
v.alpha = 0f
|
||||||
v.scaleY = 0f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hide(v: View, anim: ViewPropertyAnimator) {
|
override fun hide(v: View, anim: ViewPropertyAnimator) {
|
||||||
anim.scaleX(0f)
|
anim.alpha(0f)
|
||||||
anim.scaleY(0f)
|
anim.translationY(v.measureHeight().toFloat())
|
||||||
anim.interpolator = AccelerateDecelerateInterpolator()
|
anim.interpolator = AccelerateInterpolator()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun show(v: View, anim: ViewPropertyAnimator) {
|
override fun show(v: View, anim: ViewPropertyAnimator) {
|
||||||
anim.scaleY(1f)
|
anim.alpha(1f)
|
||||||
anim.scaleX(1f)
|
anim.translationY(0f)
|
||||||
anim.interpolator = AccelerateDecelerateInterpolator()
|
anim.interpolator = DecelerateInterpolator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.koitharu.kotatsu.utils.ext
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
|
||||||
|
var TextView.textAndVisible: CharSequence?
|
||||||
|
inline get() = text?.takeIf { visibility == View.VISIBLE }
|
||||||
|
set(value) {
|
||||||
|
text = value
|
||||||
|
isGone = value.isNullOrEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
var TextView.drawableStart: Drawable?
|
||||||
|
inline get() = compoundDrawablesRelative[0]
|
||||||
|
set(value) {
|
||||||
|
val dr = compoundDrawablesRelative
|
||||||
|
setCompoundDrawablesRelativeWithIntrinsicBounds(value, dr[1], dr[2], dr[3])
|
||||||
|
}
|
||||||
@@ -40,13 +40,6 @@ inline fun <reified T : View> ViewGroup.inflate(@LayoutRes resId: Int) =
|
|||||||
val RecyclerView.hasItems: Boolean
|
val RecyclerView.hasItems: Boolean
|
||||||
get() = (adapter?.itemCount ?: 0) > 0
|
get() = (adapter?.itemCount ?: 0) > 0
|
||||||
|
|
||||||
var TextView.textAndVisible: CharSequence?
|
|
||||||
get() = text?.takeIf { visibility == View.VISIBLE }
|
|
||||||
set(value) {
|
|
||||||
text = value
|
|
||||||
isGone = value.isNullOrEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fun <T> ChipGroup.addChips(data: Iterable<T>, action: ChipsFactory.(T) -> Chip) {
|
inline fun <T> ChipGroup.addChips(data: Iterable<T>, action: ChipsFactory.(T) -> Chip) {
|
||||||
val factory = ChipsFactory(context)
|
val factory = ChipsFactory(context)
|
||||||
data.forEach {
|
data.forEach {
|
||||||
|
|||||||
11
app/src/main/res/drawable/bg_reader_indicator.xml
Normal file
11
app/src/main/res/drawable/bg_reader_indicator.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="16dp" />
|
||||||
|
<solid android:color="@color/dim" />
|
||||||
|
<padding
|
||||||
|
android:bottom="8dp"
|
||||||
|
android:left="12dp"
|
||||||
|
android:right="12dp"
|
||||||
|
android:top="8dp" />
|
||||||
|
</shape>
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<FrameLayout
|
<FrameLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:keepScreenOn="true">
|
android:keepScreenOn="true">
|
||||||
@@ -11,14 +12,19 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<ProgressBar
|
<org.koitharu.kotatsu.reader.ui.ReaderToastView
|
||||||
android:id="@+id/progressBar_bottom"
|
android:id="@+id/toastView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:indeterminate="true"
|
android:layout_gravity="bottom|center_horizontal"
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_marginBottom="20dp"
|
android:layout_marginBottom="20dp"
|
||||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal" />
|
android:background="@drawable/bg_reader_indicator"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:drawablePadding="6dp"
|
||||||
|
android:textAppearance="?android:textAppearanceSmall"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:theme="@style/ThemeOverlay.MaterialComponents.Dark"
|
||||||
|
tools:text="@string/loading_" />
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbar_top"
|
android:id="@+id/appbar_top"
|
||||||
@@ -45,7 +51,8 @@
|
|||||||
android:background="@color/dim"
|
android:background="@color/dim"
|
||||||
android:elevation="0dp"
|
android:elevation="0dp"
|
||||||
android:theme="@style/AppToolbarTheme"
|
android:theme="@style/AppToolbarTheme"
|
||||||
app:elevation="0dp">
|
app:elevation="0dp"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/toolbar_bottom"
|
android:id="@+id/toolbar_bottom"
|
||||||
|
|||||||
Reference in New Issue
Block a user