UI improvements
This commit is contained in:
@@ -78,6 +78,10 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
get() = prefs.getInt(KEY_GRID_SIZE, 100)
|
get() = prefs.getInt(KEY_GRID_SIZE, 100)
|
||||||
set(value) = prefs.edit { putInt(KEY_GRID_SIZE, value) }
|
set(value) = prefs.edit { putInt(KEY_GRID_SIZE, value) }
|
||||||
|
|
||||||
|
var gridSizePages: Int
|
||||||
|
get() = prefs.getInt(KEY_GRID_SIZE_PAGES, 100)
|
||||||
|
set(value) = prefs.edit { putInt(KEY_GRID_SIZE_PAGES, value) }
|
||||||
|
|
||||||
var historyListMode: ListMode
|
var historyListMode: ListMode
|
||||||
get() = prefs.getEnumValue(KEY_LIST_MODE_HISTORY, listMode)
|
get() = prefs.getEnumValue(KEY_LIST_MODE_HISTORY, listMode)
|
||||||
set(value) = prefs.edit { putEnumValue(KEY_LIST_MODE_HISTORY, value) }
|
set(value) = prefs.edit { putEnumValue(KEY_LIST_MODE_HISTORY, value) }
|
||||||
@@ -527,6 +531,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
const val KEY_SEARCH_HISTORY_CLEAR = "search_history_clear"
|
const val KEY_SEARCH_HISTORY_CLEAR = "search_history_clear"
|
||||||
const val KEY_UPDATES_FEED_CLEAR = "updates_feed_clear"
|
const val KEY_UPDATES_FEED_CLEAR = "updates_feed_clear"
|
||||||
const val KEY_GRID_SIZE = "grid_size"
|
const val KEY_GRID_SIZE = "grid_size"
|
||||||
|
const val KEY_GRID_SIZE_PAGES = "grid_size_pages"
|
||||||
const val KEY_REMOTE_SOURCES = "remote_sources"
|
const val KEY_REMOTE_SOURCES = "remote_sources"
|
||||||
const val KEY_LOCAL_STORAGE = "local_storage"
|
const val KEY_LOCAL_STORAGE = "local_storage"
|
||||||
const val KEY_READER_DOUBLE_PAGES = "reader_double_pages"
|
const val KEY_READER_DOUBLE_PAGES = "reader_double_pages"
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package org.koitharu.kotatsu.details.ui
|
||||||
|
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import com.google.android.material.slider.LabelFormatter
|
||||||
|
import com.google.android.material.slider.Slider
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.setValueRounded
|
||||||
|
import org.koitharu.kotatsu.core.util.progress.IntPercentLabelFormatter
|
||||||
|
import org.koitharu.kotatsu.details.ui.pager.ChaptersPagesSheet.Companion.TAB_CHAPTERS
|
||||||
|
import org.koitharu.kotatsu.details.ui.pager.ChaptersPagesSheet.Companion.TAB_PAGES
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
class ChapterPagesMenuProvider(
|
||||||
|
private val viewModel: DetailsViewModel,
|
||||||
|
private val sheet: BaseAdaptiveSheet<*>,
|
||||||
|
private val pager: ViewPager2,
|
||||||
|
private val settings: AppSettings,
|
||||||
|
) : OnBackPressedCallback(false), MenuProvider, SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener,
|
||||||
|
Slider.OnChangeListener {
|
||||||
|
|
||||||
|
private var expandedItemRef: WeakReference<MenuItem>? = null
|
||||||
|
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
val tab = getCurrentTab()
|
||||||
|
when (tab) {
|
||||||
|
TAB_CHAPTERS -> {
|
||||||
|
menuInflater.inflate(R.menu.opt_chapters, menu)
|
||||||
|
menu.findItem(R.id.action_search)?.run {
|
||||||
|
setOnActionExpandListener(this@ChapterPagesMenuProvider)
|
||||||
|
(actionView as? SearchView)?.setupChaptersSearchView()
|
||||||
|
}
|
||||||
|
menu.findItem(R.id.action_search)?.isVisible = viewModel.isChaptersEmpty.value == false
|
||||||
|
menu.findItem(R.id.action_reversed)?.isChecked = viewModel.isChaptersReversed.value == true
|
||||||
|
menu.findItem(R.id.action_grid_view)?.isChecked = viewModel.isChaptersInGridView.value == true
|
||||||
|
}
|
||||||
|
|
||||||
|
TAB_PAGES -> {
|
||||||
|
menuInflater.inflate(R.menu.opt_pages, menu)
|
||||||
|
menu.findItem(R.id.action_grid_size)?.run {
|
||||||
|
setOnActionExpandListener(this@ChapterPagesMenuProvider)
|
||||||
|
(actionView as? Slider)?.setupPagesSizeSlider()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
|
||||||
|
R.id.action_reversed -> {
|
||||||
|
viewModel.setChaptersReversed(!menuItem.isChecked)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.action_grid_view -> {
|
||||||
|
viewModel.setChaptersInGridView(!menuItem.isChecked)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
expandedItemRef?.get()?.collapseActionView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||||
|
expandedItemRef = WeakReference(item)
|
||||||
|
sheet.expandAndLock()
|
||||||
|
isEnabled = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||||
|
expandedItemRef = null
|
||||||
|
isEnabled = false
|
||||||
|
(item.actionView as? SearchView)?.setQuery("", false)
|
||||||
|
viewModel.performChapterSearch(null)
|
||||||
|
sheet.unlock()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueryTextSubmit(query: String?): Boolean = false
|
||||||
|
|
||||||
|
override fun onQueryTextChange(newText: String?): Boolean {
|
||||||
|
viewModel.performChapterSearch(newText)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
|
||||||
|
if (fromUser) {
|
||||||
|
settings.gridSizePages = value.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SearchView.setupChaptersSearchView() {
|
||||||
|
setOnQueryTextListener(this@ChapterPagesMenuProvider)
|
||||||
|
setIconifiedByDefault(false)
|
||||||
|
queryHint = context.getString(R.string.search_chapters)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Slider.setupPagesSizeSlider() {
|
||||||
|
valueFrom = 50f
|
||||||
|
valueTo = 150f
|
||||||
|
stepSize = 5f
|
||||||
|
isTickVisible = false
|
||||||
|
labelBehavior = LabelFormatter.LABEL_FLOATING
|
||||||
|
setLabelFormatter(IntPercentLabelFormatter(context))
|
||||||
|
setValueRounded(settings.gridSizePages.toFloat())
|
||||||
|
addOnChangeListener(this@ChapterPagesMenuProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getCurrentTab(): Int {
|
||||||
|
var page = pager.currentItem
|
||||||
|
if (page > 0 && pager.adapter?.itemCount == 2) { // no Pages page
|
||||||
|
page++ // shift
|
||||||
|
}
|
||||||
|
return page
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.details.ui
|
|
||||||
|
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import androidx.activity.OnBackPressedCallback
|
|
||||||
import androidx.appcompat.widget.SearchView
|
|
||||||
import androidx.core.view.MenuProvider
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
|
||||||
import java.lang.ref.WeakReference
|
|
||||||
|
|
||||||
class ChaptersMenuProvider2(
|
|
||||||
private val viewModel: DetailsViewModel,
|
|
||||||
private val sheet: BaseAdaptiveSheet<*>,
|
|
||||||
) : OnBackPressedCallback(false), MenuProvider, SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener {
|
|
||||||
|
|
||||||
private var searchItemRef: WeakReference<MenuItem>? = null
|
|
||||||
|
|
||||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
|
||||||
menuInflater.inflate(R.menu.opt_chapters, menu)
|
|
||||||
val searchMenuItem = menu.findItem(R.id.action_search)
|
|
||||||
searchMenuItem.setOnActionExpandListener(this)
|
|
||||||
val searchView = searchMenuItem.actionView as SearchView
|
|
||||||
searchView.setOnQueryTextListener(this)
|
|
||||||
searchView.setIconifiedByDefault(false)
|
|
||||||
searchView.queryHint = searchMenuItem.title
|
|
||||||
searchItemRef = WeakReference(searchMenuItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrepareMenu(menu: Menu) {
|
|
||||||
menu.findItem(R.id.action_search)?.isVisible = viewModel.isChaptersEmpty.value == false
|
|
||||||
menu.findItem(R.id.action_reversed)?.isChecked = viewModel.isChaptersReversed.value == true
|
|
||||||
menu.findItem(R.id.action_grid_view)?.isChecked = viewModel.isChaptersInGridView.value == true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean = when (menuItem.itemId) {
|
|
||||||
R.id.action_reversed -> {
|
|
||||||
viewModel.setChaptersReversed(!menuItem.isChecked)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_grid_view -> {
|
|
||||||
viewModel.setChaptersInGridView(!menuItem.isChecked)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handleOnBackPressed() {
|
|
||||||
searchItemRef?.get()?.collapseActionView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
|
||||||
sheet.expandAndLock()
|
|
||||||
isEnabled = true
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
|
||||||
isEnabled = false
|
|
||||||
(item.actionView as? SearchView)?.setQuery("", false)
|
|
||||||
viewModel.performChapterSearch(null)
|
|
||||||
sheet.unlock()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onQueryTextSubmit(query: String?): Boolean = false
|
|
||||||
|
|
||||||
override fun onQueryTextChange(newText: String?): Boolean {
|
|
||||||
viewModel.performChapterSearch(newText)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -92,7 +92,6 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
|
|||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
import org.koitharu.kotatsu.parsers.util.ellipsize
|
import org.koitharu.kotatsu.parsers.util.ellipsize
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
||||||
import org.koitharu.kotatsu.reader.ui.thumbnails.PagesThumbnailsSheet
|
|
||||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
|
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
|
||||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
|
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
|
||||||
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
import org.koitharu.kotatsu.search.ui.MangaListActivity
|
||||||
@@ -316,19 +315,6 @@ class DetailsActivity2 :
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_pages_thumbs -> {
|
|
||||||
val history = viewModel.historyInfo.value.history
|
|
||||||
PagesThumbnailsSheet.show(
|
|
||||||
fm = supportFragmentManager,
|
|
||||||
manga = viewModel.manga.value ?: return false,
|
|
||||||
chapterId = history?.chapterId
|
|
||||||
?: viewModel.chapters.value.firstOrNull()?.chapter?.id
|
|
||||||
?: return false,
|
|
||||||
currentPage = history?.page ?: 0,
|
|
||||||
)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -606,8 +592,11 @@ class DetailsActivity2 :
|
|||||||
append(branch.count.toString())
|
append(branch.count.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menu.menu.add(Menu.NONE, Menu.NONE, i, title)
|
val item = menu.menu.add(R.id.group_branches, Menu.NONE, i, title)
|
||||||
|
item.isCheckable = true
|
||||||
|
item.isChecked = branch.isSelected
|
||||||
}
|
}
|
||||||
|
menu.menu.setGroupCheckable(R.id.group_branches, true, true)
|
||||||
menu.setOnMenuItemClickListener {
|
menu.setOnMenuItemClickListener {
|
||||||
viewModel.setSelectedBranch(branches.getOrNull(it.order)?.name)
|
viewModel.setSelectedBranch(branches.getOrNull(it.order)?.name)
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import org.koitharu.kotatsu.core.util.ext.setTabsEnabled
|
|||||||
import org.koitharu.kotatsu.core.util.ext.showDistinct
|
import org.koitharu.kotatsu.core.util.ext.showDistinct
|
||||||
import org.koitharu.kotatsu.core.util.ext.withArgs
|
import org.koitharu.kotatsu.core.util.ext.withArgs
|
||||||
import org.koitharu.kotatsu.databinding.SheetChaptersPagesBinding
|
import org.koitharu.kotatsu.databinding.SheetChaptersPagesBinding
|
||||||
import org.koitharu.kotatsu.details.ui.ChaptersMenuProvider2
|
import org.koitharu.kotatsu.details.ui.ChapterPagesMenuProvider
|
||||||
import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), Actio
|
|||||||
binding.pager.setCurrentItem(args.getInt(ARG_TAB, settings.defaultDetailsTab), false)
|
binding.pager.setCurrentItem(args.getInt(ARG_TAB, settings.defaultDetailsTab), false)
|
||||||
binding.tabs.isVisible = adapter.itemCount > 1
|
binding.tabs.isVisible = adapter.itemCount > 1
|
||||||
|
|
||||||
val menuProvider = ChaptersMenuProvider2(viewModel, this)
|
val menuProvider = ChapterPagesMenuProvider(viewModel, this, binding.pager, settings)
|
||||||
onBackPressedDispatcher.addCallback(viewLifecycleOwner, menuProvider)
|
onBackPressedDispatcher.addCallback(viewLifecycleOwner, menuProvider)
|
||||||
binding.toolbar.addMenuProvider(menuProvider)
|
binding.toolbar.addMenuProvider(menuProvider)
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ class ChaptersPagesSheet : BaseAdaptiveSheet<SheetChaptersPagesBinding>(), Actio
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onPageChanged(position: Int) {
|
private fun onPageChanged(position: Int) {
|
||||||
viewBinding?.toolbar?.menuView?.isVisible = position == 0
|
viewBinding?.toolbar?.invalidateMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -30,14 +30,12 @@ import org.koitharu.kotatsu.core.util.ext.observeEvent
|
|||||||
import org.koitharu.kotatsu.core.util.ext.showOrHide
|
import org.koitharu.kotatsu.core.util.ext.showOrHide
|
||||||
import org.koitharu.kotatsu.databinding.FragmentPagesBinding
|
import org.koitharu.kotatsu.databinding.FragmentPagesBinding
|
||||||
import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListSpanResolver
|
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||||
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
|
import org.koitharu.kotatsu.list.ui.adapter.TypedListSpacingDecoration
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
import org.koitharu.kotatsu.reader.ui.ReaderActivity.IntentBuilder
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderNavigationCallback
|
import org.koitharu.kotatsu.reader.ui.ReaderNavigationCallback
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||||
import org.koitharu.kotatsu.reader.ui.thumbnails.OnPageSelectListener
|
|
||||||
import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail
|
import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail
|
||||||
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter
|
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -58,7 +56,7 @@ class PagesFragment :
|
|||||||
lateinit var settings: AppSettings
|
lateinit var settings: AppSettings
|
||||||
|
|
||||||
private var thumbnailsAdapter: PageThumbnailAdapter? = null
|
private var thumbnailsAdapter: PageThumbnailAdapter? = null
|
||||||
private var spanResolver: MangaListSpanResolver? = null
|
private var spanResolver: PagesGridSpanResolver? = null
|
||||||
private var scrollListener: ScrollListener? = null
|
private var scrollListener: ScrollListener? = null
|
||||||
|
|
||||||
private val spanSizeLookup = SpanSizeLookup()
|
private val spanSizeLookup = SpanSizeLookup()
|
||||||
@@ -85,19 +83,19 @@ class PagesFragment :
|
|||||||
|
|
||||||
override fun onViewBindingCreated(binding: FragmentPagesBinding, savedInstanceState: Bundle?) {
|
override fun onViewBindingCreated(binding: FragmentPagesBinding, savedInstanceState: Bundle?) {
|
||||||
super.onViewBindingCreated(binding, savedInstanceState)
|
super.onViewBindingCreated(binding, savedInstanceState)
|
||||||
spanResolver = MangaListSpanResolver(binding.root.resources)
|
spanResolver = PagesGridSpanResolver(binding.root.resources)
|
||||||
thumbnailsAdapter = PageThumbnailAdapter(
|
thumbnailsAdapter = PageThumbnailAdapter(
|
||||||
coil = coil,
|
coil = coil,
|
||||||
lifecycleOwner = viewLifecycleOwner,
|
lifecycleOwner = viewLifecycleOwner,
|
||||||
clickListener = this@PagesFragment,
|
clickListener = this@PagesFragment,
|
||||||
)
|
)
|
||||||
|
viewModel.gridScale.observe(viewLifecycleOwner, ::onGridScaleChanged) // before rv initialization
|
||||||
with(binding.recyclerView) {
|
with(binding.recyclerView) {
|
||||||
addItemDecoration(TypedListSpacingDecoration(context, false))
|
addItemDecoration(TypedListSpacingDecoration(context, false))
|
||||||
adapter = thumbnailsAdapter
|
adapter = thumbnailsAdapter
|
||||||
setHasFixedSize(true)
|
setHasFixedSize(true)
|
||||||
isNestedScrollingEnabled = false
|
isNestedScrollingEnabled = false
|
||||||
addOnLayoutChangeListener(spanResolver)
|
addOnLayoutChangeListener(spanResolver)
|
||||||
spanResolver?.setGridSize(settings.gridSize / 100f, this)
|
|
||||||
addOnScrollListener(ScrollListener().also { scrollListener = it })
|
addOnScrollListener(ScrollListener().also { scrollListener = it })
|
||||||
(layoutManager as GridLayoutManager).let {
|
(layoutManager as GridLayoutManager).let {
|
||||||
it.spanSizeLookup = spanSizeLookup
|
it.spanSizeLookup = spanSizeLookup
|
||||||
@@ -174,6 +172,11 @@ class PagesFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onGridScaleChanged(scale: Float) {
|
||||||
|
spanSizeLookup.invalidateCache()
|
||||||
|
spanResolver?.setGridSize(scale, requireViewBinding().recyclerView)
|
||||||
|
}
|
||||||
|
|
||||||
private fun onNoChaptersChanged(isNoChapters: Boolean) {
|
private fun onNoChaptersChanged(isNoChapters: Boolean) {
|
||||||
with(viewBinding ?: return) {
|
with(viewBinding ?: return) {
|
||||||
textViewHolder.isVisible = isNoChapters
|
textViewHolder.isVisible = isNoChapters
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.koitharu.kotatsu.details.ui.pager.pages
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
class PagesGridSpanResolver(
|
||||||
|
resources: Resources,
|
||||||
|
) : View.OnLayoutChangeListener {
|
||||||
|
|
||||||
|
var spanCount = 3
|
||||||
|
private set
|
||||||
|
|
||||||
|
private val gridWidth = resources.getDimension(R.dimen.preferred_grid_width)
|
||||||
|
private val spacing = resources.getDimension(R.dimen.grid_spacing)
|
||||||
|
private var cellWidth = -1f
|
||||||
|
|
||||||
|
override fun onLayoutChange(
|
||||||
|
v: View?,
|
||||||
|
left: Int,
|
||||||
|
top: Int,
|
||||||
|
right: Int,
|
||||||
|
bottom: Int,
|
||||||
|
oldLeft: Int,
|
||||||
|
oldTop: Int,
|
||||||
|
oldRight: Int,
|
||||||
|
oldBottom: Int,
|
||||||
|
) {
|
||||||
|
if (cellWidth <= 0f) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val rv = v as? RecyclerView ?: return
|
||||||
|
val width = abs(right - left)
|
||||||
|
if (width == 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resolveGridSpanCount(width)
|
||||||
|
(rv.layoutManager as? GridLayoutManager)?.spanCount = spanCount
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setGridSize(scaleFactor: Float, rv: RecyclerView) {
|
||||||
|
cellWidth = (gridWidth * scaleFactor) + spacing
|
||||||
|
val lm = rv.layoutManager as? GridLayoutManager ?: return
|
||||||
|
val innerWidth = lm.width - lm.paddingEnd - lm.paddingStart
|
||||||
|
if (innerWidth > 0) {
|
||||||
|
resolveGridSpanCount(innerWidth)
|
||||||
|
lm.spanCount = spanCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resolveGridSpanCount(width: Int) {
|
||||||
|
val estimatedCount = (width / cellWidth).roundToInt()
|
||||||
|
spanCount = estimatedCount.coerceAtLeast(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
package org.koitharu.kotatsu.details.ui.pager.pages
|
package org.koitharu.kotatsu.details.ui.pager.pages
|
||||||
|
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.plus
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.util.ext.firstNotNull
|
import org.koitharu.kotatsu.core.util.ext.firstNotNull
|
||||||
import org.koitharu.kotatsu.details.data.MangaDetails
|
import org.koitharu.kotatsu.details.data.MangaDetails
|
||||||
@@ -18,6 +22,7 @@ import javax.inject.Inject
|
|||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class PagesViewModel @Inject constructor(
|
class PagesViewModel @Inject constructor(
|
||||||
private val chaptersLoader: ChaptersLoader,
|
private val chaptersLoader: ChaptersLoader,
|
||||||
|
private val settings: AppSettings,
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
@@ -29,6 +34,12 @@ class PagesViewModel @Inject constructor(
|
|||||||
val isLoadingUp = MutableStateFlow(false)
|
val isLoadingUp = MutableStateFlow(false)
|
||||||
val isLoadingDown = MutableStateFlow(false)
|
val isLoadingDown = MutableStateFlow(false)
|
||||||
|
|
||||||
|
val gridScale = settings.observeAsStateFlow(
|
||||||
|
scope = viewModelScope + Dispatchers.Default,
|
||||||
|
key = AppSettings.KEY_GRID_SIZE_PAGES,
|
||||||
|
valueProducer = { gridSizePages / 100f },
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadingJob = launchLoadingJob(Dispatchers.Default) {
|
loadingJob = launchLoadingJob(Dispatchers.Default) {
|
||||||
val firstState = state.firstNotNull()
|
val firstState = state.firstNotNull()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
|
package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
|
||||||
|
|
||||||
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||||
@@ -23,6 +24,6 @@ fun mangaCategoryAD(
|
|||||||
binding.checkableImageView.setChecked(item.isChecked, ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED in payloads)
|
binding.checkableImageView.setChecked(item.isChecked, ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED in payloads)
|
||||||
binding.textViewTitle.text = item.category.title
|
binding.textViewTitle.text = item.category.title
|
||||||
binding.imageViewTracker.isVisible = item.category.isTrackingEnabled && item.isTrackerEnabled
|
binding.imageViewTracker.isVisible = item.category.isTrackingEnabled && item.isTrackerEnabled
|
||||||
binding.imageViewVisible.isVisible = item.category.isVisibleInLibrary
|
binding.imageViewHidden.isGone = item.category.isVisibleInLibrary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="16dp"
|
android:width="16dp"
|
||||||
android:height="16dp"
|
android:height="16dp"
|
||||||
android:tint="?attr/colorPrimary"
|
android:tint="@color/common_green"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
|
|||||||
12
app/src/main/res/drawable/ic_filter_menu.xml
Normal file
12
app/src/main/res/drawable/ic_filter_menu.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#000"
|
||||||
|
android:pathData="M12 18.88A1 1 0 0 1 11.71 19.71A1 1 0 0 1 10.3 19.71L6.3 15.71A1 1 0 0 1 6 14.87V9.75L1.21 3.62A1 1 0 0 1 1.38 2.22A1 1 0 0 1 2 2H16A1 1 0 0 1 16.62 2.22A1 1 0 0 1 16.79 3.62L12 9.75V18.88M4 4L8 9.06V14.58L10 16.58V9.05L14 4M13 16L18 21L23 16Z" />
|
||||||
|
</vector>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
android:layout_margin="@dimen/screen_padding"
|
android:layout_margin="@dimen/screen_padding"
|
||||||
android:background="@drawable/bg_circle_button"
|
android:background="@drawable/bg_circle_button"
|
||||||
android:contentDescription="@string/back"
|
android:contentDescription="@string/back"
|
||||||
android:elevation="4dp"
|
android:elevation="@dimen/m3_sys_elevation_level1"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:src="?homeAsUpIndicator" />
|
android:src="?homeAsUpIndicator" />
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:icon="@drawable/ic_reorder"
|
app:icon="@drawable/ic_filter_menu"
|
||||||
tools:text="@string/newest"
|
tools:text="@string/newest"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,13 @@
|
|||||||
android:text="@string/location"
|
android:text="@string/location"
|
||||||
android:textAppearance="?textAppearanceLabelMedium" />
|
android:textAppearance="?textAppearanceLabelMedium" />
|
||||||
|
|
||||||
<TextView
|
<org.koitharu.kotatsu.core.ui.widgets.SelectableTextView
|
||||||
android:id="@+id/textView_path"
|
android:id="@+id/textView_path"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:textAppearance="?textAppearanceBodyMedium"
|
android:textAppearance="?textAppearanceBodyMedium"
|
||||||
|
android:textIsSelectable="true"
|
||||||
tools:text="/storage/emulated/0/Manga/lorem.cbz" />
|
tools:text="/storage/emulated/0/Manga/lorem.cbz" />
|
||||||
|
|
||||||
<org.koitharu.kotatsu.core.ui.widgets.SegmentedBarView
|
<org.koitharu.kotatsu.core.ui.widgets.SegmentedBarView
|
||||||
|
|||||||
@@ -46,13 +46,13 @@
|
|||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:contentDescription="@string/check_for_new_chapters"
|
android:contentDescription="@string/check_for_new_chapters"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/imageView_visible"
|
app:layout_constraintEnd_toStartOf="@id/imageView_hidden"
|
||||||
app:layout_constraintStart_toEndOf="@id/textView_title"
|
app:layout_constraintStart_toEndOf="@id/textView_title"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_notification" />
|
app:srcCompat="@drawable/ic_notification" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imageView_visible"
|
android:id="@+id/imageView_hidden"
|
||||||
android:layout_width="14dp"
|
android:layout_width="14dp"
|
||||||
android:layout_height="14dp"
|
android:layout_height="14dp"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
@@ -61,6 +61,6 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/imageView_tracker"
|
app:layout_constraintStart_toEndOf="@id/imageView_tracker"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:srcCompat="@drawable/ic_eye" />
|
app:srcCompat="@drawable/ic_eye_off" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
14
app/src/main/res/menu/opt_pages.xml
Normal file
14
app/src/main/res/menu/opt_pages.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?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_grid_size"
|
||||||
|
android:icon="@drawable/ic_size_large"
|
||||||
|
android:orderInCategory="10"
|
||||||
|
android:title="@string/grid_size"
|
||||||
|
app:actionViewClass="com.google.android.material.slider.Slider"
|
||||||
|
app:showAsAction="ifRoom|collapseActionView" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -7,11 +7,6 @@
|
|||||||
android:icon="@drawable/ic_incognito"
|
android:icon="@drawable/ic_incognito"
|
||||||
android:title="@string/incognito_mode" />
|
android:title="@string/incognito_mode" />
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_pages_thumbs"
|
|
||||||
android:icon="@drawable/ic_grid"
|
|
||||||
android:title="@string/pages" />
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_forget"
|
android:id="@+id/action_forget"
|
||||||
android:icon="@drawable/ic_delete"
|
android:icon="@drawable/ic_delete"
|
||||||
|
|||||||
Reference in New Issue
Block a user