Migrate favorites to ViewPager2
This commit is contained in:
@@ -0,0 +1,38 @@
|
|||||||
|
package org.koitharu.kotatsu.core.ui.util
|
||||||
|
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.widget.PopupMenu
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.setOnContextClickListenerCompat
|
||||||
|
|
||||||
|
class PopupMenuMediator(
|
||||||
|
private val provider: MenuProvider,
|
||||||
|
) : View.OnLongClickListener, PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener {
|
||||||
|
|
||||||
|
override fun onLongClick(v: View): Boolean {
|
||||||
|
val menu = PopupMenu(v.context, v)
|
||||||
|
provider.onCreateMenu(menu.menu, menu.menuInflater)
|
||||||
|
provider.onPrepareMenu(menu.menu)
|
||||||
|
if (!menu.menu.hasVisibleItems()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
menu.setOnMenuItemClickListener(this)
|
||||||
|
menu.setOnDismissListener(this)
|
||||||
|
menu.show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||||
|
return provider.onMenuItemSelected(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(menu: PopupMenu) {
|
||||||
|
provider.onMenuClosed(menu.menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun attach(view: View) {
|
||||||
|
view.setOnLongClickListener(this)
|
||||||
|
view.setOnContextClickListenerCompat(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -365,6 +365,7 @@ class DetailsActivity :
|
|||||||
private fun initPager() {
|
private fun initPager() {
|
||||||
viewBinding.pager.recyclerView?.isNestedScrollingEnabled = false
|
viewBinding.pager.recyclerView?.isNestedScrollingEnabled = false
|
||||||
val adapter = DetailsPagerAdapter(this)
|
val adapter = DetailsPagerAdapter(this)
|
||||||
|
viewBinding.pager.offscreenPageLimit = 1
|
||||||
viewBinding.pager.adapter = adapter
|
viewBinding.pager.adapter = adapter
|
||||||
TabLayoutMediator(viewBinding.tabs, viewBinding.pager, adapter).attach()
|
TabLayoutMediator(viewBinding.tabs, viewBinding.pager, adapter).attach()
|
||||||
viewBinding.pager.setCurrentItem(settings.defaultDetailsTab, false)
|
viewBinding.pager.setCurrentItem(settings.defaultDetailsTab, false)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import org.koitharu.kotatsu.list.ui.model.ListModel
|
|||||||
|
|
||||||
data class FavouriteTabModel(
|
data class FavouriteTabModel(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val title: String,
|
val title: String?,
|
||||||
) : ListModel {
|
) : ListModel {
|
||||||
|
|
||||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package org.koitharu.kotatsu.favourites.ui.container
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.core.view.MenuProvider
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity
|
||||||
|
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID
|
||||||
|
|
||||||
|
class FavouriteTabPopupMenuProvider(
|
||||||
|
private val context: Context,
|
||||||
|
private val viewModel: FavouritesContainerViewModel,
|
||||||
|
private val categoryId: Long
|
||||||
|
) : MenuProvider {
|
||||||
|
|
||||||
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
|
val menuResId = if (categoryId == NO_ID) {
|
||||||
|
R.menu.popup_fav_tab_all
|
||||||
|
} else {
|
||||||
|
R.menu.popup_fav_tab
|
||||||
|
}
|
||||||
|
menuInflater.inflate(menuResId, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
|
when (menuItem.itemId) {
|
||||||
|
R.id.action_hide -> viewModel.hide(categoryId)
|
||||||
|
R.id.action_edit -> context.startActivity(
|
||||||
|
FavouritesCategoryEditActivity.newIntent(context, categoryId),
|
||||||
|
)
|
||||||
|
|
||||||
|
R.id.action_delete -> confirmDelete()
|
||||||
|
|
||||||
|
else -> return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun confirmDelete() {
|
||||||
|
MaterialAlertDialogBuilder(
|
||||||
|
context,
|
||||||
|
com.google.android.material.R.style.ThemeOverlay_Material3_MaterialAlertDialog_Centered,
|
||||||
|
).setMessage(R.string.categories_delete_confirm)
|
||||||
|
.setTitle(R.string.remove_category)
|
||||||
|
.setIcon(R.drawable.ic_delete)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.remove) { _, _ ->
|
||||||
|
viewModel.deleteCategory(categoryId)
|
||||||
|
}.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,46 @@
|
|||||||
package org.koitharu.kotatsu.favourites.ui.container
|
package org.koitharu.kotatsu.favourites.ui.container
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.recyclerview.widget.AdapterListUpdateCallback
|
||||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
import androidx.recyclerview.widget.AsyncDifferConfig
|
||||||
|
import androidx.recyclerview.widget.AsyncListDiffer
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.asExecutor
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
import kotlinx.coroutines.flow.FlowCollector
|
||||||
|
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
|
||||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
|
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
|
||||||
import org.koitharu.kotatsu.parsers.util.replaceWith
|
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
class FavouritesContainerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment),
|
||||||
class FavouritesContainerAdapter(
|
|
||||||
fm: FragmentManager
|
|
||||||
) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT),
|
|
||||||
FlowCollector<List<FavouriteTabModel>> {
|
FlowCollector<List<FavouriteTabModel>> {
|
||||||
|
|
||||||
private val dataSet = ArrayList<FavouriteTabModel>()
|
private val differ = AsyncListDiffer(
|
||||||
|
AdapterListUpdateCallback(this),
|
||||||
|
AsyncDifferConfig.Builder(ListModelDiffCallback<FavouriteTabModel>())
|
||||||
|
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
|
||||||
override fun getCount(): Int = dataSet.size
|
override fun getItemCount(): Int = differ.currentList.size
|
||||||
|
|
||||||
override fun getItem(position: Int): Fragment {
|
override fun getItemId(position: Int): Long {
|
||||||
val item = dataSet[position]
|
return differ.currentList[position].id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun containsItem(itemId: Long): Boolean {
|
||||||
|
return differ.currentList.any { x -> x.id == itemId }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createFragment(position: Int): Fragment {
|
||||||
|
val item = differ.currentList[position]
|
||||||
return FavouritesListFragment.newInstance(item.id)
|
return FavouritesListFragment.newInstance(item.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPageTitle(position: Int): CharSequence {
|
override suspend fun emit(value: List<FavouriteTabModel>) = suspendCoroutine { cont ->
|
||||||
return dataSet[position].title
|
differ.submitList(value, ContinuationResumeRunnable(cont))
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun emit(value: List<FavouriteTabModel>) {
|
fun getItem(position: Int): FavouriteTabModel = differ.currentList[position]
|
||||||
dataSet.replaceWith(value)
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.favourites.ui.container
|
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.recyclerview.widget.AdapterListUpdateCallback
|
|
||||||
import androidx.recyclerview.widget.AsyncDifferConfig
|
|
||||||
import androidx.recyclerview.widget.AsyncListDiffer
|
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.asExecutor
|
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
|
||||||
import org.koitharu.kotatsu.core.util.ContinuationResumeRunnable
|
|
||||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment
|
|
||||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
|
|
||||||
// FIXME migrate to ViewPager2 in FavouritesContainerFragment
|
|
||||||
class FavouritesContainerAdapter2(fragment: Fragment) :
|
|
||||||
FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle),
|
|
||||||
TabConfigurationStrategy,
|
|
||||||
FlowCollector<List<FavouriteTabModel>> {
|
|
||||||
|
|
||||||
private val differ = AsyncListDiffer(
|
|
||||||
AdapterListUpdateCallback(this),
|
|
||||||
AsyncDifferConfig.Builder(ListModelDiffCallback<FavouriteTabModel>())
|
|
||||||
.setBackgroundThreadExecutor(Dispatchers.Default.limitedParallelism(2).asExecutor())
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun getItemCount(): Int = differ.currentList.size
|
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long {
|
|
||||||
return differ.currentList[position].id
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun containsItem(itemId: Long): Boolean {
|
|
||||||
return differ.currentList.any { x -> x.id == itemId }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment {
|
|
||||||
val item = differ.currentList[position]
|
|
||||||
return FavouritesListFragment.newInstance(item.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
|
|
||||||
val item = differ.currentList[position]
|
|
||||||
tab.text = item.title
|
|
||||||
tab.tag = item
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun emit(value: List<FavouriteTabModel>) = suspendCoroutine { cont ->
|
|
||||||
differ.submitList(value, ContinuationResumeRunnable(cont))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,14 +12,18 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||||
import org.koitharu.kotatsu.core.ui.util.ActionModeListener
|
import org.koitharu.kotatsu.core.ui.util.ActionModeListener
|
||||||
|
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
|
||||||
import org.koitharu.kotatsu.core.util.ext.addMenuProvider
|
import org.koitharu.kotatsu.core.util.ext.addMenuProvider
|
||||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||||
import org.koitharu.kotatsu.core.util.ext.observe
|
import org.koitharu.kotatsu.core.util.ext.observe
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.recyclerView
|
||||||
import org.koitharu.kotatsu.core.util.ext.setTabsEnabled
|
import org.koitharu.kotatsu.core.util.ext.setTabsEnabled
|
||||||
import org.koitharu.kotatsu.core.util.ext.setTextAndVisible
|
import org.koitharu.kotatsu.core.util.ext.setTextAndVisible
|
||||||
import org.koitharu.kotatsu.databinding.FragmentFavouritesContainerBinding
|
import org.koitharu.kotatsu.databinding.FragmentFavouritesContainerBinding
|
||||||
@@ -43,15 +47,21 @@ class FavouritesContainerFragment : BaseFragment<FragmentFavouritesContainerBind
|
|||||||
|
|
||||||
override fun onViewBindingCreated(binding: FragmentFavouritesContainerBinding, savedInstanceState: Bundle?) {
|
override fun onViewBindingCreated(binding: FragmentFavouritesContainerBinding, savedInstanceState: Bundle?) {
|
||||||
super.onViewBindingCreated(binding, savedInstanceState)
|
super.onViewBindingCreated(binding, savedInstanceState)
|
||||||
val adapter = FavouritesContainerAdapter(childFragmentManager)
|
val pagerAdapter = FavouritesContainerAdapter(this)
|
||||||
binding.pager.adapter = adapter
|
binding.pager.adapter = pagerAdapter
|
||||||
binding.tabs.setupWithViewPager(binding.pager)
|
binding.pager.offscreenPageLimit = 99 // FIXME
|
||||||
binding.pager.offscreenPageLimit = 1
|
binding.pager.recyclerView?.isNestedScrollingEnabled = false
|
||||||
|
TabLayoutMediator(
|
||||||
|
binding.tabs,
|
||||||
|
binding.pager,
|
||||||
|
FavouritesTabConfigurationStrategy(pagerAdapter, viewModel),
|
||||||
|
).attach()
|
||||||
binding.stubEmpty.setOnInflateListener(this)
|
binding.stubEmpty.setOnInflateListener(this)
|
||||||
actionModeDelegate.addListener(this)
|
actionModeDelegate.addListener(this)
|
||||||
viewModel.categories.observe(viewLifecycleOwner, adapter)
|
viewModel.categories.observe(viewLifecycleOwner, pagerAdapter)
|
||||||
viewModel.isEmpty.observe(viewLifecycleOwner, ::onEmptyStateChanged)
|
viewModel.isEmpty.observe(viewLifecycleOwner, ::onEmptyStateChanged)
|
||||||
addMenuProvider(FavouritesContainerMenuProvider(binding.root.context))
|
addMenuProvider(FavouritesContainerMenuProvider(binding.root.context))
|
||||||
|
viewModel.onActionDone.observeEvent(viewLifecycleOwner, ReversibleActionObserver(binding.pager))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
|||||||
@@ -4,30 +4,80 @@ 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.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.core.prefs.observeAsFlow
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.util.ext.mapItems
|
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||||
|
import org.koitharu.kotatsu.core.ui.util.ReversibleHandle
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||||
|
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class FavouritesContainerViewModel @Inject constructor(
|
class FavouritesContainerViewModel @Inject constructor(
|
||||||
favouritesRepository: FavouritesRepository,
|
private val settings: AppSettings,
|
||||||
|
private val favouritesRepository: FavouritesRepository,
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||||
|
|
||||||
private val categoriesStateFlow = favouritesRepository.observeCategoriesForLibrary()
|
private val categoriesStateFlow = favouritesRepository.observeCategoriesForLibrary()
|
||||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)
|
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)
|
||||||
|
|
||||||
val categories = categoriesStateFlow.filterNotNull()
|
val categories = combine(
|
||||||
.mapItems { FavouriteTabModel(it.id, it.title) }
|
categoriesStateFlow.filterNotNull(),
|
||||||
.distinctUntilChanged()
|
observeAllFavouritesVisibility(),
|
||||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
|
) { list, showAll ->
|
||||||
|
list.toUi(showAll)
|
||||||
|
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
|
||||||
|
|
||||||
val isEmpty = categoriesStateFlow.map {
|
val isEmpty = categoriesStateFlow.map {
|
||||||
it?.isEmpty() == true
|
it?.isEmpty() == true
|
||||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false)
|
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false)
|
||||||
|
|
||||||
|
private fun List<FavouriteCategory>.toUi(showAll: Boolean): List<FavouriteTabModel> {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
val result = ArrayList<FavouriteTabModel>(if (showAll) size + 1 else size)
|
||||||
|
if (showAll) {
|
||||||
|
result.add(FavouriteTabModel(NO_ID, null))
|
||||||
|
}
|
||||||
|
mapTo(result) { FavouriteTabModel(it.id, it.title) }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide(categoryId: Long) {
|
||||||
|
launchJob(Dispatchers.Default) {
|
||||||
|
if (categoryId == NO_ID) {
|
||||||
|
settings.isAllFavouritesVisible = false
|
||||||
|
} else {
|
||||||
|
favouritesRepository.updateCategory(categoryId, isVisibleInLibrary = false)
|
||||||
|
val reverse = ReversibleHandle {
|
||||||
|
favouritesRepository.updateCategory(categoryId, isVisibleInLibrary = true)
|
||||||
|
}
|
||||||
|
onActionDone.call(ReversibleAction(R.string.category_hidden_done, reverse))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCategory(categoryId: Long) {
|
||||||
|
launchJob(Dispatchers.Default) {
|
||||||
|
favouritesRepository.removeCategories(setOf(categoryId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeAllFavouritesVisibility() = settings.observeAsFlow(
|
||||||
|
key = AppSettings.KEY_ALL_FAVOURITES_VISIBLE,
|
||||||
|
valueProducer = { isAllFavouritesVisible },
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.koitharu.kotatsu.favourites.ui.container
|
||||||
|
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
|
import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.ui.util.PopupMenuMediator
|
||||||
|
|
||||||
|
class FavouritesTabConfigurationStrategy(
|
||||||
|
private val adapter: FavouritesContainerAdapter,
|
||||||
|
private val viewModel: FavouritesContainerViewModel,
|
||||||
|
) : TabConfigurationStrategy {
|
||||||
|
|
||||||
|
override fun onConfigureTab(tab: TabLayout.Tab, position: Int) {
|
||||||
|
val item = adapter.getItem(position)
|
||||||
|
tab.text = item.title ?: tab.view.context.getString(R.string.all_favourites)
|
||||||
|
tab.tag = item
|
||||||
|
PopupMenuMediator(FavouriteTabPopupMenuProvider(tab.view.context, viewModel, item.id)).attach(tab.view)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.koitharu.kotatsu.favourites.ui.list
|
package org.koitharu.kotatsu.favourites.ui.list
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -11,10 +10,8 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
|
||||||
import org.koitharu.kotatsu.core.util.ext.addMenuProvider
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.sortedByOrdinal
|
import org.koitharu.kotatsu.core.util.ext.sortedByOrdinal
|
||||||
import org.koitharu.kotatsu.core.util.ext.withArgs
|
import org.koitharu.kotatsu.core.util.ext.withArgs
|
||||||
import org.koitharu.kotatsu.databinding.FragmentListBinding
|
|
||||||
import org.koitharu.kotatsu.list.domain.ListSortOrder
|
import org.koitharu.kotatsu.list.domain.ListSortOrder
|
||||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
@@ -29,13 +26,6 @@ class FavouritesListFragment : MangaListFragment(), PopupMenu.OnMenuItemClickLis
|
|||||||
val categoryId
|
val categoryId
|
||||||
get() = viewModel.categoryId
|
get() = viewModel.categoryId
|
||||||
|
|
||||||
override fun onViewBindingCreated(binding: FragmentListBinding, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewBindingCreated(binding, savedInstanceState)
|
|
||||||
if (viewModel.categoryId != NO_ID) {
|
|
||||||
addMenuProvider(FavouritesListMenuProvider(binding.root.context, viewModel))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onScrolledToEnd() = Unit
|
override fun onScrolledToEnd() = Unit
|
||||||
|
|
||||||
override fun onFilterClick(view: View?) {
|
override fun onFilterClick(view: View?) {
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.favourites.ui.list
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import androidx.core.view.MenuProvider
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity
|
|
||||||
|
|
||||||
class FavouritesListMenuProvider(
|
|
||||||
private val context: Context,
|
|
||||||
private val viewModel: FavouritesListViewModel,
|
|
||||||
) : MenuProvider {
|
|
||||||
|
|
||||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
|
||||||
menuInflater.inflate(R.menu.opt_favourites, menu)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
|
||||||
return when (menuItem.itemId) {
|
|
||||||
R.id.action_edit -> {
|
|
||||||
context.startActivity(FavouritesCategoryEditActivity.newIntent(context, viewModel.categoryId))
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
app:tabGravity="start"
|
app:tabGravity="start"
|
||||||
app:tabMode="scrollable" />
|
app:tabMode="scrollable" />
|
||||||
|
|
||||||
<org.koitharu.kotatsu.core.ui.widgets.EnhancedViewPager
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/pager"
|
android:id="@+id/pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
18
app/src/main/res/menu/popup_fav_tab.xml
Normal file
18
app/src/main/res/menu/popup_fav_tab.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_edit"
|
||||||
|
android:title="@string/edit_category"
|
||||||
|
android:titleCondensed="@string/edit" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_delete"
|
||||||
|
android:title="@string/delete" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_hide"
|
||||||
|
android:title="@string/hide" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
9
app/src/main/res/menu/popup_fav_tab_all.xml
Normal file
9
app/src/main/res/menu/popup_fav_tab_all.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_hide"
|
||||||
|
android:title="@string/hide" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -558,4 +558,5 @@
|
|||||||
<string name="default_tab">Default tab</string>
|
<string name="default_tab">Default tab</string>
|
||||||
<string name="mark_as_completed">Mark as completed</string>
|
<string name="mark_as_completed">Mark as completed</string>
|
||||||
<string name="mark_as_completed_prompt">Mark selected manga as completely read?\n\nWarning: current reading progress will be lost.</string>
|
<string name="mark_as_completed_prompt">Mark selected manga as completely read?\n\nWarning: current reading progress will be lost.</string>
|
||||||
</resources>
|
<string name="category_hidden_done">This category was hidden from the main screen and is accessible through Menu → Manage categories</string>
|
||||||
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user