diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/CheckableImageView.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/CheckableImageView.kt index 9c8366293..5d601d67c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/CheckableImageView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/widgets/CheckableImageView.kt @@ -5,6 +5,7 @@ import android.os.Parcel import android.os.Parcelable import android.os.Parcelable.Creator import android.util.AttributeSet +import android.view.View import android.widget.Checkable import androidx.annotation.AttrRes import androidx.appcompat.widget.AppCompatImageView @@ -61,6 +62,12 @@ class CheckableImageView @JvmOverloads constructor( } } + class ToggleOnClickListener : OnClickListener { + override fun onClick(view: View) { + (view as? Checkable)?.toggle() + } + } + fun interface OnCheckedChangeListener { fun onCheckedChanged(view: CheckableImageView, isChecked: Boolean) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 5784153d3..2b65c60a3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -11,10 +11,6 @@ import androidx.collection.arraySetOf import androidx.core.content.edit import androidx.preference.PreferenceManager import com.google.android.material.color.DynamicColors -import java.io.File -import java.text.DateFormat -import java.text.SimpleDateFormat -import java.util.* import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.flow.callbackFlow @@ -24,6 +20,10 @@ import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.ext.getEnumValue import org.koitharu.kotatsu.utils.ext.putEnumValue import org.koitharu.kotatsu.utils.ext.toUriOrNull +import java.io.File +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.* class AppSettings(context: Context) { @@ -67,6 +67,10 @@ class AppSettings(context: Context) { get() = prefs.getBoolean(KEY_TRAFFIC_WARNING, true) set(value) = prefs.edit { putBoolean(KEY_TRAFFIC_WARNING, value) } + var isAllFavouritesVisible: Boolean + get() = prefs.getBoolean(KEY_ALL_FAVOURITES_VISIBLE, true) + set(value) = prefs.edit { putBoolean(KEY_ALL_FAVOURITES_VISIBLE, value) } + val isUpdateCheckingEnabled: Boolean get() = prefs.getBoolean(KEY_APP_UPDATE_AUTO, true) @@ -278,6 +282,7 @@ class AppSettings(context: Context) { const val KEY_SEARCH_SINGLE_SOURCE = "search_single_source" const val KEY_DOWNLOADS_PARALLELISM = "downloads_parallelism" const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown" + const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible" // About const val KEY_APP_UPDATE = "app_update" diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt index 9cd6e751e..8222c0f2b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt @@ -15,7 +15,7 @@ val favouritesModule viewModel { categoryId -> FavouritesListViewModel(categoryId.get(), get(), get(), get()) } - viewModel { FavouritesCategoriesViewModel(get()) } + viewModel { FavouritesCategoriesViewModel(get(), get()) } viewModel { manga -> MangaCategoriesViewModel(manga.get(), get()) } diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt index 5cb19fda5..731d7ff5e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt @@ -64,7 +64,7 @@ class FavouritesRepository(private val db: MangaDatabase) { createdAt = System.currentTimeMillis(), sortKey = db.favouriteCategoriesDao.getNextSortKey(), categoryId = 0, - order = SortOrder.UPDATED.name, + order = SortOrder.NEWEST.name, ) val id = db.favouriteCategoriesDao.insert(entity) return entity.toFavouriteCategory(id) diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt index 72b0566b8..4433f978d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt @@ -21,12 +21,11 @@ import org.koitharu.kotatsu.databinding.FragmentFavouritesBinding import org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity import org.koitharu.kotatsu.favourites.ui.categories.CategoriesEditDelegate import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel import org.koitharu.kotatsu.main.ui.AppBarOwner -import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.measureHeight import org.koitharu.kotatsu.utils.ext.resolveDp -import java.util.* class FavouritesContainerFragment : BaseFragment(), @@ -53,15 +52,15 @@ class FavouritesContainerFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val adapter = FavouritesPagerAdapter(this, this) - viewModel.categories.value?.let { - adapter.replaceData(wrapCategories(it)) + viewModel.visibleCategories.value?.let { + adapter.replaceData(it) } binding.pager.adapter = adapter pagerAdapter = adapter TabLayoutMediator(binding.tabs, binding.pager, adapter).attach() actionModeDelegate.addListener(this, viewLifecycleOwner) - viewModel.categories.observe(viewLifecycleOwner, ::onCategoriesChanged) + viewModel.visibleCategories.observe(viewLifecycleOwner, ::onCategoriesChanged) viewModel.onError.observe(viewLifecycleOwner, ::onError) } @@ -86,7 +85,8 @@ class FavouritesContainerFragment : top = headerHeight - insets.top ) binding.pager.updatePadding( - top = -headerHeight + resources.resolveDp(8) // 8 dp is needed so that the top of the list is not attached to tabs (visible when ActionMode is active) + // 8 dp is needed so that the top of the list is not attached to tabs (visible when ActionMode is active) + top = -headerHeight + resources.resolveDp(8) ) binding.tabs.apply { updatePadding( @@ -99,8 +99,8 @@ class FavouritesContainerFragment : } } - private fun onCategoriesChanged(categories: List) { - pagerAdapter?.replaceData(wrapCategories(categories)) + private fun onCategoriesChanged(categories: List) { + pagerAdapter?.replaceData(categories) } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -122,26 +122,11 @@ class FavouritesContainerFragment : Snackbar.make(binding.pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show() } - override fun onTabLongClick(tabView: View, category: FavouriteCategory): Boolean { - val menuRes = if (category.id == 0L) R.menu.popup_category_empty else R.menu.popup_category - val menu = PopupMenu(tabView.context, tabView) - menu.inflate(menuRes) - createOrderSubmenu(menu.menu, category) - menu.setOnMenuItemClickListener { - when (it.itemId) { - R.id.action_remove -> editDelegate.deleteCategory(category) - R.id.action_rename -> editDelegate.renameCategory(category) - R.id.action_create -> editDelegate.createCategory() - R.id.action_order -> return@setOnMenuItemClickListener false - else -> { - val order = CategoriesActivity.SORT_ORDERS.getOrNull(it.order) - ?: return@setOnMenuItemClickListener false - viewModel.setCategoryOrder(category.id, order) - } - } - true + override fun onTabLongClick(tabView: View, item: CategoryListModel): Boolean { + when (item) { + is CategoryListModel.All -> showAllCategoriesMenu(tabView) + is CategoryListModel.CategoryItem -> showCategoryMenu(tabView, item.category) } - menu.show() return true } @@ -157,13 +142,6 @@ class FavouritesContainerFragment : viewModel.createCategory(name) } - private fun wrapCategories(categories: List): List { - val data = ArrayList(categories.size + 1) - data += FavouriteCategory(0L, getString(R.string.all_favourites), -1, SortOrder.NEWEST, Date()) - data += categories - return data - } - private fun createOrderSubmenu(menu: Menu, category: FavouriteCategory) { val submenu = menu.findItem(R.id.action_order)?.subMenu ?: return for ((i, item) in CategoriesActivity.SORT_ORDERS.withIndex()) { @@ -181,6 +159,40 @@ class FavouritesContainerFragment : } } + private fun showCategoryMenu(tabView: View, category: FavouriteCategory) { + val menu = PopupMenu(tabView.context, tabView) + menu.inflate(R.menu.popup_category) + createOrderSubmenu(menu.menu, category) + menu.setOnMenuItemClickListener { + when (it.itemId) { + R.id.action_remove -> editDelegate.deleteCategory(category) + R.id.action_rename -> editDelegate.renameCategory(category) + R.id.action_create -> editDelegate.createCategory() + R.id.action_order -> return@setOnMenuItemClickListener false + else -> { + val order = CategoriesActivity.SORT_ORDERS.getOrNull(it.order) + ?: return@setOnMenuItemClickListener false + viewModel.setCategoryOrder(category.id, order) + } + } + true + } + menu.show() + } + + private fun showAllCategoriesMenu(tabView: View) { + val menu = PopupMenu(tabView.context, tabView) + menu.inflate(R.menu.popup_category_all) + menu.setOnMenuItemClickListener { + when (it.itemId) { + R.id.action_create -> editDelegate.createCategory() + R.id.action_hide -> viewModel.setAllCategoriesVisible(false) + } + true + } + menu.show() + } + companion object { fun newInstance() = FavouritesContainerFragment() diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesPagerAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesPagerAdapter.kt index 29de80809..329e06751 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesPagerAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesPagerAdapter.kt @@ -7,14 +7,16 @@ import androidx.recyclerview.widget.DiffUtil import androidx.viewpager2.adapter.FragmentStateAdapter import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator -import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment class FavouritesPagerAdapter( fragment: Fragment, private val longClickListener: FavouritesTabLongClickListener ) : FragmentStateAdapter(fragment.childFragmentManager, fragment.viewLifecycleOwner.lifecycle), - TabLayoutMediator.TabConfigurationStrategy, View.OnLongClickListener { + TabLayoutMediator.TabConfigurationStrategy, + View.OnLongClickListener { private val differ = AsyncListDiffer(this, DiffCallback()) @@ -35,12 +37,15 @@ class FavouritesPagerAdapter( override fun onConfigureTab(tab: TabLayout.Tab, position: Int) { val item = differ.currentList[position] - tab.text = item.title + tab.text = when (item) { + is CategoryListModel.All -> tab.view.context.getString(R.string.all_favourites) + is CategoryListModel.CategoryItem -> item.category.title + } tab.view.tag = item.id tab.view.setOnLongClickListener(this) } - fun replaceData(data: List) { + fun replaceData(data: List) { differ.submitList(data) } @@ -50,16 +55,22 @@ class FavouritesPagerAdapter( return longClickListener.onTabLongClick(v, item) } - private class DiffCallback : DiffUtil.ItemCallback() { + private class DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: FavouriteCategory, - newItem: FavouriteCategory - ): Boolean = oldItem.id == newItem.id + oldItem: CategoryListModel, + newItem: CategoryListModel + ): Boolean = when { + oldItem is CategoryListModel.All && newItem is CategoryListModel.All -> true + oldItem is CategoryListModel.CategoryItem && newItem is CategoryListModel.CategoryItem -> { + oldItem.category.id == newItem.category.id + } + else -> false + } override fun areContentsTheSame( - oldItem: FavouriteCategory, - newItem: FavouriteCategory - ): Boolean = oldItem.id == newItem.id && oldItem.title == newItem.title + oldItem: CategoryListModel, + newItem: CategoryListModel + ): Boolean = oldItem == newItem } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesTabLongClickListener.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesTabLongClickListener.kt index acc4f89c0..13fca87c9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesTabLongClickListener.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesTabLongClickListener.kt @@ -1,9 +1,9 @@ package org.koitharu.kotatsu.favourites.ui import android.view.View -import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel fun interface FavouritesTabLongClickListener { - fun onTabLongClick(tabView: View, category: FavouriteCategory): Boolean + fun onTabLongClick(tabView: View, item: CategoryListModel): Boolean } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/AllCategoriesToggleListener.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/AllCategoriesToggleListener.kt new file mode 100644 index 000000000..380722b84 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/AllCategoriesToggleListener.kt @@ -0,0 +1,6 @@ +package org.koitharu.kotatsu.favourites.ui.categories + +interface AllCategoriesToggleListener { + + fun onAllCategoriesToggle(isVisible: Boolean) +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt index 9caeb87c8..5a2eaf8df 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesActivity.kt @@ -21,6 +21,7 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.ui.titleRes import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.measureHeight @@ -29,7 +30,7 @@ class CategoriesActivity : BaseActivity(), OnListItemClickListener, View.OnClickListener, - CategoriesEditDelegate.CategoriesEditCallback { + CategoriesEditDelegate.CategoriesEditCallback, AllCategoriesToggleListener { private val viewModel by viewModel() @@ -41,7 +42,7 @@ class CategoriesActivity : super.onCreate(savedInstanceState) setContentView(ActivityCategoriesBinding.inflate(layoutInflater)) supportActionBar?.setDisplayHomeAsUpEnabled(true) - adapter = CategoriesAdapter(this) + adapter = CategoriesAdapter(this, this) editDelegate = CategoriesEditDelegate(this, this) binding.recyclerView.setHasFixedSize(true) binding.recyclerView.adapter = adapter @@ -49,7 +50,7 @@ class CategoriesActivity : reorderHelper = ItemTouchHelper(ReorderHelperCallback()) reorderHelper.attachToRecyclerView(binding.recyclerView) - viewModel.categories.observe(this, ::onCategoriesChanged) + viewModel.allCategories.observe(this, ::onCategoriesChanged) viewModel.onError.observe(this, ::onError) } @@ -84,6 +85,10 @@ class CategoriesActivity : return true } + override fun onAllCategoriesToggle(isVisible: Boolean) { + viewModel.setAllCategoriesVisible(isVisible) + } + override fun onWindowInsetsChanged(insets: Insets) { binding.fabAdd.updateLayoutParams { rightMargin = topMargin + insets.right @@ -97,7 +102,7 @@ class CategoriesActivity : ) } - private fun onCategoriesChanged(categories: List) { + private fun onCategoriesChanged(categories: List) { adapter.items = categories binding.textViewHolder.isVisible = categories.isEmpty() } @@ -138,13 +143,19 @@ class CategoriesActivity : ItemTouchHelper.DOWN or ItemTouchHelper.UP, 0 ) { + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit + override fun onMove( recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder, - ): Boolean = true + ): Boolean = viewHolder.itemViewType == target.itemViewType - override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit + override fun canDropOver( + recyclerView: RecyclerView, + current: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder, + ): Boolean = current.itemViewType == target.itemViewType override fun onMoved( recyclerView: RecyclerView, @@ -158,6 +169,8 @@ class CategoriesActivity : super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y) viewModel.reorderCategories(fromPos, toPos) } + + override fun isLongPressDragEnabled(): Boolean = false } companion object { diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesAdapter.kt index adf19ca9c..e13b31e00 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesAdapter.kt @@ -4,13 +4,18 @@ import androidx.recyclerview.widget.DiffUtil import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel +import org.koitharu.kotatsu.favourites.ui.categories.adapter.allCategoriesAD +import org.koitharu.kotatsu.favourites.ui.categories.adapter.categoryAD class CategoriesAdapter( onItemClickListener: OnListItemClickListener, -) : AsyncListDifferDelegationAdapter(DiffCallback()) { + allCategoriesToggleListener: AllCategoriesToggleListener, +) : AsyncListDifferDelegationAdapter(DiffCallback()) { init { delegatesManager.addDelegate(categoryAD(onItemClickListener)) + .addDelegate(allCategoriesAD(allCategoriesToggleListener)) setHasStableIds(true) } @@ -18,28 +23,23 @@ class CategoriesAdapter( return items[position].id } - private class DiffCallback : DiffUtil.ItemCallback() { + private class DiffCallback : DiffUtil.ItemCallback() { override fun areItemsTheSame( - oldItem: FavouriteCategory, - newItem: FavouriteCategory, - ): Boolean { - return oldItem.id == newItem.id - } + oldItem: CategoryListModel, + newItem: CategoryListModel, + ): Boolean = oldItem.id == newItem.id override fun areContentsTheSame( - oldItem: FavouriteCategory, - newItem: FavouriteCategory, - ): Boolean { - return oldItem.id == newItem.id && oldItem.title == newItem.title - && oldItem.order == newItem.order - } + oldItem: CategoryListModel, + newItem: CategoryListModel, + ): Boolean = oldItem == newItem override fun getChangePayload( - oldItem: FavouriteCategory, - newItem: FavouriteCategory, + oldItem: CategoryListModel, + newItem: CategoryListModel, ): Any? = when { - oldItem.title == newItem.title && oldItem.order != newItem.order -> newItem.order + oldItem is CategoryListModel.All && newItem is CategoryListModel.All -> Unit else -> super.getChangePayload(oldItem, newItem) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt index c87e44c76..7aac74e62 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt @@ -3,20 +3,36 @@ package org.koitharu.kotatsu.favourites.ui.categories import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.* import org.koitharu.kotatsu.base.ui.BaseViewModel +import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.favourites.domain.FavouritesRepository +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct import java.util.* class FavouritesCategoriesViewModel( - private val repository: FavouritesRepository + private val repository: FavouritesRepository, + private val settings: AppSettings, ) : BaseViewModel() { private var reorderJob: Job? = null - val categories = repository.observeCategories() - .asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default) + val allCategories = combine( + repository.observeCategories(), + observeAllCategoriesVisible(), + ) { list, showAll -> + mapCategories(list, showAll, true) + }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default) + + val visibleCategories = combine( + repository.observeCategories(), + observeAllCategoriesVisible(), + ) { list, showAll -> + mapCategories(list, showAll, showAll) + }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default) fun createCategory(name: String) { launchJob { @@ -42,14 +58,40 @@ class FavouritesCategoriesViewModel( } } + fun setAllCategoriesVisible(isVisible: Boolean) { + settings.isAllFavouritesVisible = isVisible + } + fun reorderCategories(oldPos: Int, newPos: Int) { val prevJob = reorderJob reorderJob = launchJob(Dispatchers.Default) { prevJob?.join() - val items = categories.value ?: error("This should not happen") + val items = allCategories.value ?: error("This should not happen") val ids = items.mapTo(ArrayList(items.size)) { it.id } Collections.swap(ids, oldPos, newPos) + ids.remove(0L) repository.reorderCategories(ids) } } + + private fun mapCategories( + categories: List, + isAllCategoriesVisible: Boolean, + withAllCategoriesItem: Boolean, + ): List { + val result = ArrayList(categories.size + 1) + if (withAllCategoriesItem) { + result.add(CategoryListModel.All(isAllCategoriesVisible)) + } + categories.mapTo(result) { + CategoryListModel.CategoryItem(it) + } + return result + } + + private fun observeAllCategoriesVisible() = settings.observe() + .filter { it == AppSettings.KEY_ALL_FAVOURITES_VISIBLE } + .map { settings.isAllFavouritesVisible } + .onStart { emit(settings.isAllFavouritesVisible) } + .distinctUntilChanged() } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/AllCategoriesAD.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/AllCategoriesAD.kt new file mode 100644 index 000000000..113198bfa --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/AllCategoriesAD.kt @@ -0,0 +1,20 @@ +package org.koitharu.kotatsu.favourites.ui.categories.adapter + +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding +import org.koitharu.kotatsu.databinding.ItemCategoriesAllBinding +import org.koitharu.kotatsu.favourites.ui.categories.AllCategoriesToggleListener + +fun allCategoriesAD( + allCategoriesToggleListener: AllCategoriesToggleListener, +) = adapterDelegateViewBinding( + { inflater, parent -> ItemCategoriesAllBinding.inflate(inflater, parent, false) } +) { + + binding.imageViewToggle.setOnClickListener { + allCategoriesToggleListener.onAllCategoriesToggle(!item.isVisible) + } + + bind { + binding.imageViewToggle.isChecked = item.isVisible + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt similarity index 68% rename from app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt rename to app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt index 97b38d926..d840b783f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt @@ -1,4 +1,4 @@ -package org.koitharu.kotatsu.favourites.ui.categories +package org.koitharu.kotatsu.favourites.ui.categories.adapter import android.view.MotionEvent import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding @@ -8,23 +8,23 @@ import org.koitharu.kotatsu.databinding.ItemCategoryBinding fun categoryAD( clickListener: OnListItemClickListener -) = adapterDelegateViewBinding( +) = adapterDelegateViewBinding( { inflater, parent -> ItemCategoryBinding.inflate(inflater, parent, false) } ) { binding.imageViewMore.setOnClickListener { - clickListener.onItemClick(item, it) + clickListener.onItemClick(item.category, it) } @Suppress("ClickableViewAccessibility") binding.imageViewHandle.setOnTouchListener { v, event -> if (event.actionMasked == MotionEvent.ACTION_DOWN) { - clickListener.onItemLongClick(item, itemView) + clickListener.onItemLongClick(item.category, itemView) } else { false } } bind { - binding.textViewTitle.text = item.title + binding.textViewTitle.text = item.category.title } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryListModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryListModel.kt new file mode 100644 index 000000000..8326f8617 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryListModel.kt @@ -0,0 +1,59 @@ +package org.koitharu.kotatsu.favourites.ui.categories.adapter + +import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.list.ui.model.ListModel + +sealed interface CategoryListModel : ListModel { + + val id: Long + + class All( + val isVisible: Boolean, + ) : CategoryListModel { + + override val id: Long = 0L + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as All + + if (isVisible != other.isVisible) return false + + return true + } + + override fun hashCode(): Int { + return isVisible.hashCode() + } + } + + class CategoryItem( + val category: FavouriteCategory, + ) : CategoryListModel { + + override val id: Long + get() = category.id + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as CategoryItem + + if (category.id != other.category.id) return false + if (category.title != other.category.title) return false + if (category.order != other.category.order) return false + + return true + } + + override fun hashCode(): Int { + var result = category.id.hashCode() + result = 31 * result + category.title.hashCode() + result = 31 * result + category.order.hashCode() + return result + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt index 60a5b6ff9..ad27cec65 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt @@ -141,10 +141,7 @@ class SourcesSettingsFragment : BaseFragment(), recyclerView: RecyclerView, current: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder, - ): Boolean = current.itemViewType == target.itemViewType && viewModel.canReorder( - current.bindingAdapterPosition, - target.bindingAdapterPosition, - ) + ): Boolean = current.itemViewType == target.itemViewType override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit diff --git a/app/src/main/res/drawable/ic_hidden.xml b/app/src/main/res/drawable/ic_hidden.xml new file mode 100644 index 000000000..82816e502 --- /dev/null +++ b/app/src/main/res/drawable/ic_hidden.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_shown.xml b/app/src/main/res/drawable/ic_shown.xml new file mode 100644 index 000000000..ee4887a82 --- /dev/null +++ b/app/src/main/res/drawable/ic_shown.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_shown_hidden.xml b/app/src/main/res/drawable/ic_shown_hidden.xml new file mode 100644 index 000000000..5405a4747 --- /dev/null +++ b/app/src/main/res/drawable/ic_shown_hidden.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_categories_all.xml b/app/src/main/res/layout/item_categories_all.xml new file mode 100644 index 000000000..8f965adf0 --- /dev/null +++ b/app/src/main/res/layout/item_categories_all.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/popup_category_empty.xml b/app/src/main/res/menu/popup_category_all.xml similarity index 70% rename from app/src/main/res/menu/popup_category_empty.xml rename to app/src/main/res/menu/popup_category_all.xml index 740312ef1..60b3bc3bd 100644 --- a/app/src/main/res/menu/popup_category_empty.xml +++ b/app/src/main/res/menu/popup_category_all.xml @@ -2,6 +2,10 @@ + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 828ad9fe6..cca5b5410 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -279,4 +279,5 @@ Helps avoid blocking your IP address Saved manga processing Chapters will be removed in the background. It can take some time + Hide \ No newline at end of file