Update reader ui
This commit is contained in:
@@ -363,10 +363,6 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
val isReaderBarEnabled: Boolean
|
val isReaderBarEnabled: Boolean
|
||||||
get() = prefs.getBoolean(KEY_READER_BAR, true)
|
get() = prefs.getBoolean(KEY_READER_BAR, true)
|
||||||
|
|
||||||
var isReaderSliderEnabled: Boolean
|
|
||||||
get() = prefs.getBoolean(KEY_READER_SLIDER, true)
|
|
||||||
set(value) = prefs.edit { putBoolean(KEY_READER_SLIDER, value) }
|
|
||||||
|
|
||||||
val isReaderKeepScreenOn: Boolean
|
val isReaderKeepScreenOn: Boolean
|
||||||
get() = prefs.getBoolean(KEY_READER_SCREEN_ON, true)
|
get() = prefs.getBoolean(KEY_READER_SCREEN_ON, true)
|
||||||
|
|
||||||
@@ -671,7 +667,6 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
const val KEY_SYNC = "sync"
|
const val KEY_SYNC = "sync"
|
||||||
const val KEY_SYNC_SETTINGS = "sync_settings"
|
const val KEY_SYNC_SETTINGS = "sync_settings"
|
||||||
const val KEY_READER_BAR = "reader_bar"
|
const val KEY_READER_BAR = "reader_bar"
|
||||||
const val KEY_READER_SLIDER = "reader_slider"
|
|
||||||
const val KEY_READER_BACKGROUND = "reader_background"
|
const val KEY_READER_BACKGROUND = "reader_background"
|
||||||
const val KEY_READER_SCREEN_ON = "reader_screen_on"
|
const val KEY_READER_SCREEN_ON = "reader_screen_on"
|
||||||
const val KEY_SHORTCUTS = "dynamic_shortcuts"
|
const val KEY_SHORTCUTS = "dynamic_shortcuts"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.core.ui.widgets
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.OnClickListener
|
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
@@ -34,7 +33,7 @@ import com.google.android.material.R as materialR
|
|||||||
class ChipsView @JvmOverloads constructor(
|
class ChipsView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = com.google.android.material.R.attr.chipGroupStyle,
|
defStyleAttr: Int = materialR.attr.chipGroupStyle,
|
||||||
) : ChipGroup(context, attrs, defStyleAttr) {
|
) : ChipGroup(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -49,6 +48,7 @@ class ChipsView @JvmOverloads constructor(
|
|||||||
onChipCloseClickListener?.onChipCloseClick(chip, data) ?: onChipClickListener?.onChipClick(chip, data)
|
onChipCloseClickListener?.onChipCloseClick(chip, data) ?: onChipClickListener?.onChipClick(chip, data)
|
||||||
}
|
}
|
||||||
private val chipStyle: Int
|
private val chipStyle: Int
|
||||||
|
private val iconsVisible: Boolean
|
||||||
var onChipClickListener: OnChipClickListener? = null
|
var onChipClickListener: OnChipClickListener? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
@@ -60,6 +60,7 @@ class ChipsView @JvmOverloads constructor(
|
|||||||
init {
|
init {
|
||||||
val ta = context.obtainStyledAttributes(attrs, R.styleable.ChipsView, defStyleAttr, 0)
|
val ta = context.obtainStyledAttributes(attrs, R.styleable.ChipsView, defStyleAttr, 0)
|
||||||
chipStyle = ta.getResourceId(R.styleable.ChipsView_chipStyle, R.style.Widget_Kotatsu_Chip)
|
chipStyle = ta.getResourceId(R.styleable.ChipsView_chipStyle, R.style.Widget_Kotatsu_Chip)
|
||||||
|
iconsVisible = ta.getBoolean(R.styleable.ChipsView_chipIconVisible, true)
|
||||||
ta.recycle()
|
ta.recycle()
|
||||||
|
|
||||||
if (isInEditMode) {
|
if (isInEditMode) {
|
||||||
@@ -170,12 +171,7 @@ class ChipsView @JvmOverloads constructor(
|
|||||||
|
|
||||||
private fun bindIcon(model: ChipModel) {
|
private fun bindIcon(model: ChipModel) {
|
||||||
when {
|
when {
|
||||||
model.isChecked -> {
|
model.isChecked -> disposeIcon()
|
||||||
imageRequest?.dispose()
|
|
||||||
imageRequest = null
|
|
||||||
chipIcon = null
|
|
||||||
isChipIconVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
model.isLoading -> {
|
model.isLoading -> {
|
||||||
imageRequest?.dispose()
|
imageRequest?.dispose()
|
||||||
@@ -184,6 +180,8 @@ class ChipsView @JvmOverloads constructor(
|
|||||||
setProgressIcon()
|
setProgressIcon()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
!iconsVisible -> disposeIcon()
|
||||||
|
|
||||||
model.iconData != null -> {
|
model.iconData != null -> {
|
||||||
val placeholder = model.icon.ifZero { materialR.drawable.navigation_empty_icon }
|
val placeholder = model.icon.ifZero { materialR.drawable.navigation_empty_icon }
|
||||||
imageRequest = ImageRequest.Builder(context)
|
imageRequest = ImageRequest.Builder(context)
|
||||||
@@ -207,14 +205,16 @@ class ChipsView @JvmOverloads constructor(
|
|||||||
isChipIconVisible = true
|
isChipIconVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> disposeIcon()
|
||||||
imageRequest?.dispose()
|
|
||||||
imageRequest = null
|
|
||||||
chipIcon = null
|
|
||||||
isChipIconVisible = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun disposeIcon() {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageRequest = null
|
||||||
|
chipIcon = null
|
||||||
|
isChipIconVisible = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class InternalChipClickListener : OnClickListener {
|
private inner class InternalChipClickListener : OnClickListener {
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import android.content.Context
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import com.google.android.material.button.MaterialButtonGroup
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.databinding.ViewZoomBinding
|
import org.koitharu.kotatsu.databinding.ViewZoomBinding
|
||||||
|
|
||||||
class ZoomControl @JvmOverloads constructor(
|
class ZoomControl @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
) : LinearLayout(context, attrs), View.OnClickListener {
|
) : MaterialButtonGroup(context, attrs), View.OnClickListener {
|
||||||
|
|
||||||
private val binding = ViewZoomBinding.inflate(LayoutInflater.from(context), this)
|
private val binding = ViewZoomBinding.inflate(LayoutInflater.from(context), this)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.koitharu.kotatsu.core.util
|
package org.koitharu.kotatsu.core.util
|
||||||
|
|
||||||
import androidx.core.os.LocaleListCompat
|
import androidx.core.os.LocaleListCompat
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.indexOfContains
|
||||||
import org.koitharu.kotatsu.core.util.ext.iterator
|
import org.koitharu.kotatsu.core.util.ext.iterator
|
||||||
|
|
||||||
class LocaleStringComparator : Comparator<String?> {
|
class LocaleStringComparator : Comparator<String?> {
|
||||||
@@ -14,7 +15,7 @@ class LocaleStringComparator : Comparator<String?> {
|
|||||||
val set = HashSet<String?>(localeList.size() + 1)
|
val set = HashSet<String?>(localeList.size() + 1)
|
||||||
set.add(null)
|
set.add(null)
|
||||||
for (locale in localeList) {
|
for (locale in localeList) {
|
||||||
val lang = locale.getDisplayLanguage(locale).lowercase()
|
val lang = locale.getDisplayLanguage(locale)
|
||||||
if (set.add(lang)) {
|
if (set.add(lang)) {
|
||||||
add(lang)
|
add(lang)
|
||||||
}
|
}
|
||||||
@@ -23,8 +24,8 @@ class LocaleStringComparator : Comparator<String?> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun compare(a: String?, b: String?): Int {
|
override fun compare(a: String?, b: String?): Int {
|
||||||
val indexA = deviceLocales.indexOf(a?.lowercase())
|
val indexA = deviceLocales.indexOfContains(a, true)
|
||||||
val indexB = deviceLocales.indexOf(b?.lowercase())
|
val indexB = deviceLocales.indexOfContains(b, true)
|
||||||
return when {
|
return when {
|
||||||
indexA < 0 && indexB < 0 -> compareValues(a, b)
|
indexA < 0 && indexB < 0 -> compareValues(a, b)
|
||||||
indexA < 0 -> 1
|
indexA < 0 -> 1
|
||||||
|
|||||||
@@ -108,3 +108,7 @@ fun <T, R> Collection<T>.mapSortedByCount(isDescending: Boolean = true, mapper:
|
|||||||
}
|
}
|
||||||
return sorted.map { it.first }
|
return sorted.map { it.first }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Collection<CharSequence?>.indexOfContains(element: CharSequence?, ignoreCase: Boolean): Int = indexOfFirst { x ->
|
||||||
|
(x == null && element == null) || (x != null && element != null && x.contains(element, ignoreCase))
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), Actio
|
|||||||
}
|
}
|
||||||
val binding = viewBinding ?: return
|
val binding = viewBinding ?: return
|
||||||
val isActionModeStarted = actionModeDelegate?.isActionModeStarted == true
|
val isActionModeStarted = actionModeDelegate?.isActionModeStarted == true
|
||||||
binding.toolbar.menuView?.isVisible = newState != STATE_COLLAPSED && !isActionModeStarted
|
binding.toolbar.menuView?.isVisible = newState == STATE_EXPANDED && !isActionModeStarted
|
||||||
binding.splitButtonRead.isVisible = newState == STATE_COLLAPSED && !isActionModeStarted
|
binding.splitButtonRead.isVisible = newState != STATE_EXPANDED && !isActionModeStarted
|
||||||
&& viewModel is DetailsViewModel
|
&& viewModel is DetailsViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,12 +145,10 @@ class ReaderActivity :
|
|||||||
viewModel.content.observe(this) {
|
viewModel.content.observe(this) {
|
||||||
onLoadingStateChanged(viewModel.isLoading.value)
|
onLoadingStateChanged(viewModel.isLoading.value)
|
||||||
}
|
}
|
||||||
viewModel.isSliderVisible.observe(this) { updateSliderVisibility() }
|
|
||||||
viewModel.isKeepScreenOnEnabled.observe(this, this::setKeepScreenOn)
|
viewModel.isKeepScreenOnEnabled.observe(this, this::setKeepScreenOn)
|
||||||
viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged)
|
viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged)
|
||||||
val bottomMenuInvalidator = MenuInvalidator(viewBinding.toolbarBottom)
|
viewModel.isBookmarkAdded.observe(this, MenuInvalidator(this))
|
||||||
viewModel.isBookmarkAdded.observe(this, bottomMenuInvalidator)
|
viewModel.isPagesSheetEnabled.observe(this, MenuInvalidator(viewBinding.toolbarBottom))
|
||||||
viewModel.isPagesSheetEnabled.observe(this, bottomMenuInvalidator)
|
|
||||||
viewModel.onShowToast.observeEvent(this) { msgId ->
|
viewModel.onShowToast.observeEvent(this) { msgId ->
|
||||||
Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT)
|
Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT)
|
||||||
.setAnchorView(viewBinding.appbarBottom)
|
.setAnchorView(viewBinding.appbarBottom)
|
||||||
@@ -159,7 +157,8 @@ class ReaderActivity :
|
|||||||
viewModel.isZoomControlsEnabled.observe(this) {
|
viewModel.isZoomControlsEnabled.observe(this) {
|
||||||
viewBinding.zoomControl.isVisible = it
|
viewBinding.zoomControl.isVisible = it
|
||||||
}
|
}
|
||||||
viewBinding.toolbarBottom.addMenuProvider(ReaderMenuProvider(this, readerManager, viewModel))
|
addMenuProvider(ReaderMenuTopProvider(viewModel))
|
||||||
|
viewBinding.toolbarBottom.addMenuProvider(ReaderMenuBottomProvider(this, readerManager, viewModel))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getParentActivityIntent(): Intent? {
|
override fun getParentActivityIntent(): Intent? {
|
||||||
@@ -234,7 +233,7 @@ class ReaderActivity :
|
|||||||
rawX >= viewBinding.root.width - gestureInsets.right ||
|
rawX >= viewBinding.root.width - gestureInsets.right ||
|
||||||
rawY >= viewBinding.root.height - gestureInsets.bottom ||
|
rawY >= viewBinding.root.height - gestureInsets.bottom ||
|
||||||
viewBinding.appbarTop.hasGlobalPoint(rawX, rawY) ||
|
viewBinding.appbarTop.hasGlobalPoint(rawX, rawY) ||
|
||||||
viewBinding.appbarBottom?.hasGlobalPoint(rawX, rawY) == true
|
viewBinding.appbarBottom.hasGlobalPoint(rawX, rawY) == true
|
||||||
) {
|
) {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
@@ -301,20 +300,14 @@ class ReaderActivity :
|
|||||||
.setOrdering(TransitionSet.ORDERING_TOGETHER)
|
.setOrdering(TransitionSet.ORDERING_TOGETHER)
|
||||||
.addTransition(Slide(Gravity.TOP).addTarget(viewBinding.appbarTop))
|
.addTransition(Slide(Gravity.TOP).addTarget(viewBinding.appbarTop))
|
||||||
.addTransition(Fade().addTarget(viewBinding.infoBar))
|
.addTransition(Fade().addTarget(viewBinding.infoBar))
|
||||||
viewBinding.appbarBottom?.let { bottomBar ->
|
.addTransition(Slide(Gravity.BOTTOM).addTarget(viewBinding.appbarBottom))
|
||||||
transition.addTransition(Slide(Gravity.BOTTOM).addTarget(bottomBar))
|
|
||||||
transition.addTransition(Slide(Gravity.BOTTOM).addTarget(viewBinding.floatingToolbar))
|
|
||||||
} ?: run {
|
|
||||||
transition.addTransition(Slide(Gravity.END).addTarget(viewBinding.floatingToolbar))
|
|
||||||
}
|
|
||||||
TransitionManager.beginDelayedTransition(viewBinding.root, transition)
|
TransitionManager.beginDelayedTransition(viewBinding.root, transition)
|
||||||
}
|
}
|
||||||
val isFullscreen = settings.isReaderFullscreenEnabled
|
val isFullscreen = settings.isReaderFullscreenEnabled
|
||||||
viewBinding.appbarTop.isVisible = isUiVisible
|
viewBinding.appbarTop.isVisible = isUiVisible
|
||||||
viewBinding.appbarBottom?.isVisible = isUiVisible
|
viewBinding.appbarBottom.isVisible = isUiVisible
|
||||||
viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value)
|
viewBinding.infoBar.isGone = isUiVisible || (!viewModel.isInfoBarEnabled.value)
|
||||||
viewBinding.infoBar.isTimeVisible = isFullscreen
|
viewBinding.infoBar.isTimeVisible = isFullscreen
|
||||||
updateSliderVisibility()
|
|
||||||
systemUiController.setSystemUiVisible(isUiVisible || !isFullscreen)
|
systemUiController.setSystemUiVisible(isUiVisible || !isFullscreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,7 +320,7 @@ class ReaderActivity :
|
|||||||
right = systemBars.right,
|
right = systemBars.right,
|
||||||
left = systemBars.left,
|
left = systemBars.left,
|
||||||
)
|
)
|
||||||
viewBinding.appbarBottom?.updateLayoutParams<MarginLayoutParams> {
|
viewBinding.appbarBottom.updateLayoutParams<MarginLayoutParams> {
|
||||||
bottomMargin = systemBars.bottom + topMargin
|
bottomMargin = systemBars.bottom + topMargin
|
||||||
rightMargin = systemBars.right + topMargin
|
rightMargin = systemBars.right + topMargin
|
||||||
leftMargin = systemBars.left + topMargin
|
leftMargin = systemBars.left + topMargin
|
||||||
@@ -383,33 +376,31 @@ class ReaderActivity :
|
|||||||
viewBinding.infoBar.update(uiState)
|
viewBinding.infoBar.update(uiState)
|
||||||
if (uiState == null) {
|
if (uiState == null) {
|
||||||
supportActionBar?.subtitle = null
|
supportActionBar?.subtitle = null
|
||||||
updateSliderVisibility()
|
viewBinding.layoutSlider.isVisible = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
supportActionBar?.subtitle = when {
|
supportActionBar?.subtitle = when {
|
||||||
uiState.incognito -> getString(R.string.incognito_mode)
|
uiState.incognito -> getString(R.string.incognito_mode)
|
||||||
else -> uiState.chapterName
|
else -> uiState.chapterName
|
||||||
}
|
}
|
||||||
if (previous?.chapterName != null && uiState.chapterName != previous.chapterName) {
|
if (uiState.chapterName != previous?.chapterName && !uiState.chapterName.isNullOrEmpty()) {
|
||||||
if (!uiState.chapterName.isNullOrEmpty()) {
|
viewBinding.toastView.showTemporary(uiState.chapterName, TOAST_DURATION)
|
||||||
viewBinding.toastView.showTemporary(uiState.chapterName, TOAST_DURATION)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (uiState.isSliderAvailable()) {
|
if (uiState.isSliderAvailable()) {
|
||||||
viewBinding.slider.valueTo = uiState.totalPages.toFloat() - 1
|
viewBinding.slider.valueTo = uiState.totalPages.toFloat() - 1
|
||||||
viewBinding.slider.setValueRounded(uiState.currentPage.toFloat())
|
viewBinding.slider.setValueRounded(uiState.currentPage.toFloat())
|
||||||
|
} else {
|
||||||
|
viewBinding.slider.valueTo = 1f
|
||||||
|
viewBinding.slider.value = 0f
|
||||||
}
|
}
|
||||||
updateSliderVisibility()
|
viewBinding.slider.isEnabled = uiState.isSliderAvailable()
|
||||||
}
|
viewBinding.buttonNext.isEnabled = uiState.hasNextChapter()
|
||||||
|
viewBinding.buttonPrev.isEnabled = uiState.hasPreviousChapter()
|
||||||
private fun updateSliderVisibility() {
|
viewBinding.layoutSlider.isVisible = true
|
||||||
viewBinding.floatingToolbar.isVisible = viewBinding.appbarTop.isVisible &&
|
|
||||||
viewModel.isSliderVisible.value &&
|
|
||||||
viewModel.uiState.value?.isSliderAvailable() == true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val TOAST_DURATION = 1500L
|
private const val TOAST_DURATION = 2000L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import androidx.fragment.app.FragmentActivity
|
|||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.nav.router
|
import org.koitharu.kotatsu.core.nav.router
|
||||||
|
|
||||||
class ReaderMenuProvider(
|
class ReaderMenuBottomProvider(
|
||||||
private val activity: FragmentActivity,
|
private val activity: FragmentActivity,
|
||||||
private val readerManager: ReaderManager,
|
private val readerManager: ReaderManager,
|
||||||
private val viewModel: ReaderViewModel,
|
private val viewModel: ReaderViewModel,
|
||||||
) : MenuProvider {
|
) : MenuProvider {
|
||||||
|
|
||||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
menuInflater.inflate(R.menu.opt_reader, menu)
|
menuInflater.inflate(R.menu.opt_reader_bottom, menu)
|
||||||
onPrepareMenu(menu) // fix, not called in toolbar
|
onPrepareMenu(menu) // fix, not called in toolbar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,15 +27,6 @@ class ReaderMenuProvider(
|
|||||||
setIcon(if (viewModel.isPagesSheetEnabled.value) R.drawable.ic_grid else R.drawable.ic_list)
|
setIcon(if (viewModel.isPagesSheetEnabled.value) R.drawable.ic_grid else R.drawable.ic_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menu.findItem(R.id.action_bookmark)?.let { bookmarkItem ->
|
|
||||||
val hasPages = viewModel.content.value.pages.isNotEmpty()
|
|
||||||
bookmarkItem.isEnabled = hasPages
|
|
||||||
if (hasPages) {
|
|
||||||
val hasBookmark = viewModel.isBookmarkAdded.value
|
|
||||||
bookmarkItem.setTitle(if (hasBookmark) R.string.bookmark_remove else R.string.bookmark_add)
|
|
||||||
bookmarkItem.setIcon(if (hasBookmark) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
@@ -52,11 +43,6 @@ class ReaderMenuProvider(
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_slider -> {
|
|
||||||
viewModel.setSliderVisibility(!viewModel.isSliderVisible.value)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_bookmark -> {
|
R.id.action_bookmark -> {
|
||||||
if (viewModel.isBookmarkAdded.value) {
|
if (viewModel.isBookmarkAdded.value) {
|
||||||
viewModel.removeBookmark()
|
viewModel.removeBookmark()
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package org.koitharu.kotatsu.reader.ui
|
||||||
|
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
|
||||||
|
class ReaderMenuTopProvider(
|
||||||
|
private val viewModel: ReaderViewModel,
|
||||||
|
) : MenuProvider {
|
||||||
|
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
menuInflater.inflate(R.menu.opt_reader_top, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPrepareMenu(menu: Menu) {
|
||||||
|
menu.findItem(R.id.action_bookmark)?.let { bookmarkItem ->
|
||||||
|
val hasPages = viewModel.content.value.pages.isNotEmpty()
|
||||||
|
bookmarkItem.isEnabled = hasPages
|
||||||
|
if (hasPages) {
|
||||||
|
val hasBookmark = viewModel.isBookmarkAdded.value
|
||||||
|
bookmarkItem.setTitle(if (hasBookmark) R.string.bookmark_remove else R.string.bookmark_add)
|
||||||
|
bookmarkItem.setIcon(if (hasBookmark) R.drawable.ic_bookmark_added else R.drawable.ic_bookmark)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
return when (menuItem.itemId) {
|
||||||
|
R.id.action_bookmark -> {
|
||||||
|
if (viewModel.isBookmarkAdded.value) {
|
||||||
|
viewModel.removeBookmark()
|
||||||
|
} else {
|
||||||
|
viewModel.addBookmark()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
package org.koitharu.kotatsu.reader.ui
|
package org.koitharu.kotatsu.reader.ui
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.Gravity
|
import android.view.ViewPropertyAnimator
|
||||||
import android.view.ViewGroup
|
import android.view.animation.AccelerateInterpolator
|
||||||
|
import android.view.animation.DecelerateInterpolator
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.transition.Fade
|
|
||||||
import androidx.transition.Slide
|
|
||||||
import androidx.transition.TransitionManager
|
|
||||||
import androidx.transition.TransitionSet
|
|
||||||
import com.google.android.material.textview.MaterialTextView
|
import com.google.android.material.textview.MaterialTextView
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.getAnimationDuration
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.isAnimationsEnabled
|
||||||
|
|
||||||
class ReaderToastView @JvmOverloads constructor(
|
class ReaderToastView @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
@@ -18,6 +21,8 @@ class ReaderToastView @JvmOverloads constructor(
|
|||||||
defStyleAttr: Int = 0,
|
defStyleAttr: Int = 0,
|
||||||
) : MaterialTextView(context, attrs, defStyleAttr) {
|
) : MaterialTextView(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
|
private var currentAnimator: ViewPropertyAnimator? = null
|
||||||
|
|
||||||
private var hideRunnable = Runnable {
|
private var hideRunnable = Runnable {
|
||||||
hide()
|
hide()
|
||||||
}
|
}
|
||||||
@@ -25,8 +30,7 @@ class ReaderToastView @JvmOverloads constructor(
|
|||||||
fun show(message: CharSequence) {
|
fun show(message: CharSequence) {
|
||||||
removeCallbacks(hideRunnable)
|
removeCallbacks(hideRunnable)
|
||||||
text = message
|
text = message
|
||||||
setupTransition()
|
showImpl()
|
||||||
isVisible = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun show(@StringRes messageId: Int) {
|
fun show(@StringRes messageId: Int) {
|
||||||
@@ -40,8 +44,7 @@ class ReaderToastView @JvmOverloads constructor(
|
|||||||
|
|
||||||
fun hide() {
|
fun hide() {
|
||||||
removeCallbacks(hideRunnable)
|
removeCallbacks(hideRunnable)
|
||||||
setupTransition()
|
hideImpl()
|
||||||
isVisible = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
override fun onDetachedFromWindow() {
|
||||||
@@ -49,13 +52,41 @@ class ReaderToastView @JvmOverloads constructor(
|
|||||||
super.onDetachedFromWindow()
|
super.onDetachedFromWindow()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupTransition() {
|
private fun showImpl() {
|
||||||
val parentView = parent as? ViewGroup ?: return
|
currentAnimator?.cancel()
|
||||||
val transition = TransitionSet()
|
clearAnimation()
|
||||||
.setOrdering(TransitionSet.ORDERING_TOGETHER)
|
if (!context.isAnimationsEnabled) {
|
||||||
.addTarget(this)
|
currentAnimator = null
|
||||||
.addTransition(Slide(Gravity.BOTTOM))
|
isVisible = true
|
||||||
.addTransition(Fade())
|
return
|
||||||
TransitionManager.beginDelayedTransition(parentView, transition)
|
}
|
||||||
|
alpha = 0f
|
||||||
|
isVisible = true
|
||||||
|
currentAnimator = animate()
|
||||||
|
.alpha(1f)
|
||||||
|
.setInterpolator(DecelerateInterpolator())
|
||||||
|
.setDuration(context.getAnimationDuration(R.integer.config_shorterAnimTime))
|
||||||
|
.setListener(null)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private fun hideImpl() {
|
||||||
|
currentAnimator?.cancel()
|
||||||
|
clearAnimation()
|
||||||
|
if (!context.isAnimationsEnabled) {
|
||||||
|
currentAnimator = null
|
||||||
|
isGone = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
currentAnimator = animate()
|
||||||
|
.alpha(0f)
|
||||||
|
.setInterpolator(AccelerateInterpolator())
|
||||||
|
.setDuration(context.getAnimationDuration(R.integer.config_shorterAnimTime))
|
||||||
|
.setListener(
|
||||||
|
object : AnimatorListenerAdapter() {
|
||||||
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
|
isGone = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ import kotlinx.coroutines.flow.first
|
|||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
@@ -132,12 +130,6 @@ class ReaderViewModel @Inject constructor(
|
|||||||
valueProducer = { readerAnimation },
|
valueProducer = { readerAnimation },
|
||||||
)
|
)
|
||||||
|
|
||||||
val isSliderVisible = settings.observeAsStateFlow(
|
|
||||||
scope = viewModelScope + Dispatchers.Default,
|
|
||||||
key = AppSettings.KEY_READER_SLIDER,
|
|
||||||
valueProducer = { isReaderSliderEnabled },
|
|
||||||
)
|
|
||||||
|
|
||||||
val isInfoBarEnabled = settings.observeAsStateFlow(
|
val isInfoBarEnabled = settings.observeAsStateFlow(
|
||||||
scope = viewModelScope + Dispatchers.Default,
|
scope = viewModelScope + Dispatchers.Default,
|
||||||
key = AppSettings.KEY_READER_BAR,
|
key = AppSettings.KEY_READER_BAR,
|
||||||
@@ -199,10 +191,6 @@ class ReaderViewModel @Inject constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
loadImpl()
|
loadImpl()
|
||||||
settings.observe()
|
|
||||||
.onEach { key ->
|
|
||||||
if (key == AppSettings.KEY_READER_SLIDER) notifyStateChanged()
|
|
||||||
}.launchIn(viewModelScope + Dispatchers.Default)
|
|
||||||
launchJob(Dispatchers.Default) {
|
launchJob(Dispatchers.Default) {
|
||||||
val mangaId = manga.filterNotNull().first().id
|
val mangaId = manga.filterNotNull().first().id
|
||||||
appShortcutManager.notifyMangaOpened(mangaId)
|
appShortcutManager.notifyMangaOpened(mangaId)
|
||||||
@@ -220,10 +208,6 @@ class ReaderViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setSliderVisibility(visible: Boolean) {
|
|
||||||
settings.isReaderSliderEnabled = visible
|
|
||||||
}
|
|
||||||
|
|
||||||
fun switchMode(newMode: ReaderMode) {
|
fun switchMode(newMode: ReaderMode) {
|
||||||
launchJob {
|
launchJob {
|
||||||
val manga = checkNotNull(getMangaOrNull())
|
val manga = checkNotNull(getMangaOrNull())
|
||||||
@@ -459,7 +443,6 @@ class ReaderViewModel @Inject constructor(
|
|||||||
chaptersTotal = m.chapters[chapter.branch].sizeOrZero(),
|
chaptersTotal = m.chapters[chapter.branch].sizeOrZero(),
|
||||||
totalPages = chaptersLoader.getPagesCount(chapter.id),
|
totalPages = chaptersLoader.getPagesCount(chapter.id),
|
||||||
currentPage = state.page,
|
currentPage = state.page,
|
||||||
isSliderEnabled = settings.isReaderSliderEnabled,
|
|
||||||
percent = computePercent(state.chapterId, state.page),
|
percent = computePercent(state.chapterId, state.page),
|
||||||
incognito = incognitoMode.value,
|
incognito = incognitoMode.value,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ data class ReaderUiState(
|
|||||||
val totalPages: Int,
|
val totalPages: Int,
|
||||||
val percent: Float,
|
val percent: Float,
|
||||||
val incognito: Boolean,
|
val incognito: Boolean,
|
||||||
private val isSliderEnabled: Boolean,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun isSliderAvailable(): Boolean {
|
fun hasNextChapter(): Boolean = chapterNumber < chaptersTotal
|
||||||
return isSliderEnabled && totalPages > 1 && currentPage < totalPages
|
|
||||||
}
|
fun hasPreviousChapter(): Boolean = chapterNumber > 1
|
||||||
|
|
||||||
|
fun isSliderAvailable(): Boolean = totalPages > 1 && currentPage < totalPages
|
||||||
}
|
}
|
||||||
|
|||||||
4
app/src/main/res/color-v23/bg_floating_button.xml
Normal file
4
app/src/main/res/color-v23/bg_floating_button.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:alpha="0.6" android:color="?colorSurfaceBright" />
|
||||||
|
</selector>
|
||||||
5
app/src/main/res/color/bg_floating_button.xml
Normal file
5
app/src/main/res/color/bg_floating_button.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- https://stackoverflow.com/questions/54685474/theme-attributes-in-color-selector-for-api-22 -->
|
||||||
|
<item android:alpha="0.6" android:color="@color/kotatsu_surfaceBright" />
|
||||||
|
</selector>
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:keepScreenOn="true">
|
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
|
||||||
android:id="@+id/container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
<org.koitharu.kotatsu.reader.ui.ReaderInfoBarView
|
|
||||||
android:id="@+id/infoBar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="top"
|
|
||||||
android:paddingHorizontal="6dp"
|
|
||||||
android:paddingTop="8dp"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<org.koitharu.kotatsu.core.ui.widgets.ZoomControl
|
|
||||||
android:id="@+id/zoomControl"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_margin="16dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_dodgeInsetEdges="bottom"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
|
||||||
android:id="@+id/appbar_top"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:elevation="@dimen/m3_card_elevated_elevation"
|
|
||||||
app:elevation="@dimen/m3_card_elevated_elevation"
|
|
||||||
app:liftOnScroll="false">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
|
||||||
android:id="@id/toolbar"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
tools:menu="@menu/opt_reader_top" />
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
|
||||||
android:id="@+id/toolbar_bottom"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1"
|
|
||||||
tools:menu="@menu/opt_reader" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.floatingtoolbar.FloatingToolbarLayout
|
|
||||||
android:id="@+id/floating_toolbar"
|
|
||||||
style="@style/Widget.Material3.FloatingToolbar.Vertical.Vibrant"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="end|center_vertical">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/floating_toolbar_child"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical">
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="240dp"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
android:valueFrom="0"
|
|
||||||
app:labelBehavior="floating"
|
|
||||||
tools:value="6"
|
|
||||||
tools:valueTo="20" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_prev"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/slider"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/prev_chapter"
|
|
||||||
android:padding="@dimen/margin_small"
|
|
||||||
android:src="@drawable/ic_prev" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_next"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/button_prev"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/next_chapter"
|
|
||||||
android:padding="@dimen/margin_small"
|
|
||||||
android:src="@drawable/ic_next" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</com.google.android.material.floatingtoolbar.FloatingToolbarLayout>
|
|
||||||
|
|
||||||
<org.koitharu.kotatsu.reader.ui.ReaderToastView
|
|
||||||
android:id="@+id/toastView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|center_horizontal"
|
|
||||||
android:layout_marginBottom="20dp"
|
|
||||||
android:background="@drawable/bg_reader_indicator"
|
|
||||||
android:drawablePadding="6dp"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
|
||||||
android:theme="@style/ThemeOverlay.Material3.Dark"
|
|
||||||
app:layout_dodgeInsetEdges="bottom"
|
|
||||||
tools:text="@string/loading_" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_loading"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
|
||||||
android:id="@+id/progressBar"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:indeterminate="true" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView_loading"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/loading_"
|
|
||||||
android:textAppearance="?attr/textAppearanceBody2" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
|
android:spacing="2dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_dodgeInsetEdges="bottom"
|
app:layout_dodgeInsetEdges="bottom"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
@@ -66,62 +67,56 @@
|
|||||||
android:id="@+id/toolbar_bottom"
|
android:id="@+id/toolbar_bottom"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
tools:menu="@menu/opt_reader" />
|
tools:menu="@menu/opt_reader_bottom">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/layout_slider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginEnd="2dp">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_prev"
|
||||||
|
style="?actionButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:contentDescription="@string/prev_chapter"
|
||||||
|
android:src="@drawable/ic_prev"
|
||||||
|
android:tooltipText="@string/prev_chapter" />
|
||||||
|
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/slider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toStartOf="@id/button_next"
|
||||||
|
android:layout_toEndOf="@id/button_prev"
|
||||||
|
android:stepSize="1.0"
|
||||||
|
android:valueFrom="0"
|
||||||
|
app:labelBehavior="floating"
|
||||||
|
tools:value="6"
|
||||||
|
tools:valueTo="20" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_next"
|
||||||
|
style="?actionButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:contentDescription="@string/next_chapter"
|
||||||
|
android:src="@drawable/ic_next"
|
||||||
|
android:tooltipText="@string/next_chapter" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.MaterialToolbar>
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.floatingtoolbar.FloatingToolbarLayout
|
|
||||||
android:id="@+id/floating_toolbar"
|
|
||||||
style="@style/Widget.Material3.FloatingToolbar.Horizontal.Vibrant"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_dodgeInsetEdges="bottom">
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/floating_toolbar_child"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_vertical">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_prev"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/prev_chapter"
|
|
||||||
android:padding="@dimen/margin_small"
|
|
||||||
android:src="@drawable/ic_prev" />
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/slider"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_toStartOf="@id/button_next"
|
|
||||||
android:layout_toEndOf="@id/button_prev"
|
|
||||||
android:stepSize="1.0"
|
|
||||||
android:valueFrom="0"
|
|
||||||
app:labelBehavior="floating"
|
|
||||||
tools:value="6"
|
|
||||||
tools:valueTo="20" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_next"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:background="?selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/next_chapter"
|
|
||||||
android:padding="@dimen/margin_small"
|
|
||||||
android:src="@drawable/ic_next" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</com.google.android.material.floatingtoolbar.FloatingToolbarLayout>
|
|
||||||
|
|
||||||
<org.koitharu.kotatsu.reader.ui.ReaderToastView
|
<org.koitharu.kotatsu.reader.ui.ReaderToastView
|
||||||
android:id="@+id/toastView"
|
android:id="@+id/toastView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -130,6 +125,7 @@
|
|||||||
android:layout_marginBottom="20dp"
|
android:layout_marginBottom="20dp"
|
||||||
android:background="@drawable/bg_reader_indicator"
|
android:background="@drawable/bg_reader_indicator"
|
||||||
android:drawablePadding="6dp"
|
android:drawablePadding="6dp"
|
||||||
|
android:elevation="1000dp"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
android:textAppearance="?attr/textAppearanceBodySmall"
|
||||||
android:theme="@style/ThemeOverlay.Material3.Dark"
|
android:theme="@style/ThemeOverlay.Material3.Dark"
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:paddingTop="2dp"
|
android:paddingTop="2dp"
|
||||||
android:paddingBottom="6dp"
|
android:paddingBottom="6dp"
|
||||||
|
app:chipIconVisible="false"
|
||||||
app:chipStyle="@style/Widget.Kotatsu.Chip.Filter"
|
app:chipStyle="@style/Widget.Kotatsu.Chip.Filter"
|
||||||
app:singleLine="true" />
|
app:singleLine="true" />
|
||||||
|
|
||||||
|
|||||||
@@ -5,39 +5,28 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
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"
|
||||||
tools:parentTag="android.widget.LinearLayout">
|
tools:orientation="vertical"
|
||||||
|
tools:parentTag="com.google.android.material.button.MaterialButtonGroup">
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_zoom_in"
|
android:id="@+id/button_zoom_in"
|
||||||
android:layout_width="?minTouchTargetSize"
|
style="@style/Widget.Material3.Button.IconButton.Outlined"
|
||||||
android:layout_height="?minTouchTargetSize"
|
android:layout_width="wrap_content"
|
||||||
android:layout_margin="4dp"
|
android:layout_height="wrap_content"
|
||||||
android:alpha="0.8"
|
|
||||||
android:background="@drawable/bg_circle_button"
|
|
||||||
android:contentDescription="@string/zoom_in"
|
android:contentDescription="@string/zoom_in"
|
||||||
android:padding="1dp"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
android:src="@drawable/ic_zoom_in"
|
|
||||||
android:tooltipText="@string/zoom_in"
|
android:tooltipText="@string/zoom_in"
|
||||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Circle"
|
app:backgroundTint="@color/bg_floating_button"
|
||||||
app:strokeColor="?colorOutline"
|
app:icon="@drawable/ic_zoom_in" />
|
||||||
app:strokeWidth="1dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_zoom_out"
|
android:id="@+id/button_zoom_out"
|
||||||
android:layout_width="?minTouchTargetSize"
|
style="@style/Widget.Material3.Button.IconButton.Outlined"
|
||||||
android:layout_height="?minTouchTargetSize"
|
android:layout_width="wrap_content"
|
||||||
android:layout_margin="4dp"
|
android:layout_height="wrap_content"
|
||||||
android:alpha="0.8"
|
|
||||||
android:background="@drawable/bg_circle_button"
|
|
||||||
android:contentDescription="@string/zoom_out"
|
android:contentDescription="@string/zoom_out"
|
||||||
android:padding="1dp"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
android:src="@drawable/ic_zoom_out"
|
|
||||||
android:tooltipText="@string/zoom_out"
|
android:tooltipText="@string/zoom_out"
|
||||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Circle"
|
app:backgroundTint="@color/bg_floating_button"
|
||||||
app:strokeColor="?colorOutline"
|
app:icon="@drawable/ic_zoom_out" />
|
||||||
app:strokeWidth="1dp" />
|
|
||||||
|
|
||||||
|
|
||||||
</merge>
|
</merge>
|
||||||
|
|||||||
@@ -5,19 +5,6 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:ignore="AlwaysShowAction">
|
tools:ignore="AlwaysShowAction">
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_slider"
|
|
||||||
android:icon="@drawable/ic_move_horizontal"
|
|
||||||
android:title="@string/show_slider"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_bookmark"
|
|
||||||
android:enabled="false"
|
|
||||||
android:icon="@drawable/ic_bookmark"
|
|
||||||
android:title="@string/bookmark_add"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_pages_thumbs"
|
android:id="@+id/action_pages_thumbs"
|
||||||
android:icon="@drawable/ic_grid"
|
android:icon="@drawable/ic_grid"
|
||||||
13
app/src/main/res/menu/opt_reader_top.xml
Normal file
13
app/src/main/res/menu/opt_reader_top.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_bookmark"
|
||||||
|
android:enabled="false"
|
||||||
|
android:icon="@drawable/ic_bookmark"
|
||||||
|
android:title="@string/bookmark_add"
|
||||||
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -141,6 +141,7 @@
|
|||||||
|
|
||||||
<declare-styleable name="ChipsView">
|
<declare-styleable name="ChipsView">
|
||||||
<attr name="chipStyle" />
|
<attr name="chipStyle" />
|
||||||
|
<attr name="chipIconVisible" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
|
|
||||||
<declare-styleable name="ReaderInfoBarView">
|
<declare-styleable name="ReaderInfoBarView">
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ conscrypt = "2.5.2"
|
|||||||
constraintlayout = "2.2.0"
|
constraintlayout = "2.2.0"
|
||||||
coreKtx = "1.15.0"
|
coreKtx = "1.15.0"
|
||||||
coroutines = "1.9.0"
|
coroutines = "1.9.0"
|
||||||
desugar = "2.1.3"
|
desugar = "2.1.4"
|
||||||
diskLruCache = "1.4"
|
diskLruCache = "1.4"
|
||||||
fragment = "1.8.5"
|
fragment = "1.8.5"
|
||||||
gradle = "8.7.3"
|
gradle = "8.7.3"
|
||||||
@@ -27,7 +27,7 @@ ksp = "2.0.21-1.0.28"
|
|||||||
leakcanary = "3.0-alpha-8"
|
leakcanary = "3.0-alpha-8"
|
||||||
lifecycle = "2.8.7"
|
lifecycle = "2.8.7"
|
||||||
markwon = "4.6.2"
|
markwon = "4.6.2"
|
||||||
material = "1.13.0-alpha08"
|
material = "1.13.0-alpha09"
|
||||||
moshi = "1.15.2"
|
moshi = "1.15.2"
|
||||||
okhttp = "4.12.0"
|
okhttp = "4.12.0"
|
||||||
okio = "3.9.1"
|
okio = "3.9.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user