diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ListSelectionController.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ListSelectionController.kt index cc479e34a..b46da465f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ListSelectionController.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ListSelectionController.kt @@ -23,7 +23,7 @@ class ListSelectionController( private val activity: Activity, private val decoration: AbstractSelectionItemDecoration, private val registryOwner: SavedStateRegistryOwner, - private val callback: Callback, + private val callback: Callback2, ) : ActionMode.Callback, SavedStateRegistry.SavedStateProvider { private var actionMode: ActionMode? = null @@ -89,19 +89,19 @@ class ListSelectionController( } override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { - return callback.onCreateActionMode(mode, menu) + return callback.onCreateActionMode(this, mode, menu) } override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { - return callback.onPrepareActionMode(mode, menu) + return callback.onPrepareActionMode(this, mode, menu) } override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { - return callback.onActionItemClicked(mode, item) + return callback.onActionItemClicked(this, mode, item) } override fun onDestroyActionMode(mode: ActionMode) { - callback.onDestroyActionMode(mode) + callback.onDestroyActionMode(this, mode) clear() actionMode = null } @@ -114,7 +114,7 @@ class ListSelectionController( private fun notifySelectionChanged() { val count = decoration.checkedItemsCount - callback.onSelectionChanged(count) + callback.onSelectionChanged(this, count) if (count == 0) { actionMode?.finish() } else { @@ -131,17 +131,53 @@ class ListSelectionController( notifySelectionChanged() } - interface Callback : ActionMode.Callback { + @Deprecated("") + interface Callback : Callback2 { fun onSelectionChanged(count: Int) - override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean + fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean - override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean + fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean - override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean + fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean - override fun onDestroyActionMode(mode: ActionMode) = Unit + fun onDestroyActionMode(mode: ActionMode) = Unit + + override fun onSelectionChanged(controller: ListSelectionController, count: Int) { + onSelectionChanged(count) + } + + override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean { + return onCreateActionMode(mode, menu) + } + + override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean { + return onPrepareActionMode(mode, menu) + } + + override fun onActionItemClicked( + controller: ListSelectionController, + mode: ActionMode, + item: MenuItem + ): Boolean = onActionItemClicked(mode, item) + + override fun onDestroyActionMode(controller: ListSelectionController, mode: ActionMode) { + onDestroyActionMode(mode) + } + } + + interface Callback2 { + + fun onSelectionChanged(controller: ListSelectionController, count: Int) + + fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean + + fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean + + fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean + + fun onDestroyActionMode(controller: ListSelectionController, mode: ActionMode) = Unit } private inner class StateEventObserver : LifecycleEventObserver { diff --git a/app/src/main/java/org/koitharu/kotatsu/browser/BrowserActivity.kt b/app/src/main/java/org/koitharu/kotatsu/browser/BrowserActivity.kt index 442808bad..601aac6e7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/browser/BrowserActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/browser/BrowserActivity.kt @@ -11,11 +11,11 @@ import android.view.MenuItem import androidx.core.graphics.Insets import androidx.core.view.isVisible import androidx.core.view.updatePadding -import com.google.android.material.R as materialR import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseActivity import org.koitharu.kotatsu.core.network.UserAgentInterceptor import org.koitharu.kotatsu.databinding.ActivityBrowserBinding +import com.google.android.material.R as materialR @SuppressLint("SetJavaScriptEnabled") class BrowserActivity : BaseActivity(), BrowserCallback { @@ -59,8 +59,9 @@ class BrowserActivity : BaseActivity(), BrowserCallback } override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.opt_browser, menu) - return super.onCreateOptionsMenu(menu) + return true } override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index e1552900f..14b71fecb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -161,8 +161,9 @@ class DetailsActivity : } override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.opt_details, menu) - return super.onCreateOptionsMenu(menu) + return true } override fun onPrepareOptionsMenu(menu: Menu): Boolean { 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 59b432efe..95d027c4c 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 @@ -5,7 +5,10 @@ import kotlinx.coroutines.flow.* import org.koitharu.kotatsu.core.db.MangaDatabase import org.koitharu.kotatsu.core.db.entity.* import org.koitharu.kotatsu.core.model.FavouriteCategory -import org.koitharu.kotatsu.favourites.data.* +import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity +import org.koitharu.kotatsu.favourites.data.FavouriteEntity +import org.koitharu.kotatsu.favourites.data.FavouriteManga +import org.koitharu.kotatsu.favourites.data.toFavouriteCategory import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.SortOrder import org.koitharu.kotatsu.tracker.work.TrackerNotificationChannels @@ -122,6 +125,14 @@ class FavouritesRepository( channels.deleteChannel(id) } + suspend fun removeCategories(ids: Collection) { + db.withTransaction { + for (id in ids) { + removeCategory(id) + } + } + } + suspend fun setCategoryOrder(id: Long, order: SortOrder) { db.favouriteCategoriesDao.updateOrder(id, order.name) } 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 deleted file mode 100644 index bb381c5cf..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerFragment.kt +++ /dev/null @@ -1,178 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.appcompat.view.ActionMode -import androidx.appcompat.widget.PopupMenu -import androidx.core.graphics.Insets -import androidx.core.view.children -import androidx.core.view.isVisible -import androidx.core.view.updatePadding -import com.google.android.material.snackbar.Snackbar -import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayoutMediator -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.base.ui.BaseFragment -import org.koitharu.kotatsu.base.ui.util.ActionModeListener -import org.koitharu.kotatsu.core.model.FavouriteCategory -import org.koitharu.kotatsu.databinding.FragmentFavouritesBinding -import org.koitharu.kotatsu.databinding.ItemEmptyStateBinding -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.favourites.ui.categories.edit.FavouritesCategoryEditActivity -import org.koitharu.kotatsu.utils.ext.addMenuProvider -import org.koitharu.kotatsu.utils.ext.getDisplayMessage - -class FavouritesContainerFragment : - BaseFragment(), - FavouritesTabLongClickListener, - CategoriesEditDelegate.CategoriesEditCallback, - ActionModeListener, - View.OnClickListener { - - private val viewModel by viewModel() - private val editDelegate by lazy(LazyThreadSafetyMode.NONE) { - CategoriesEditDelegate(requireContext(), this) - } - private var pagerAdapter: FavouritesPagerAdapter? = null - private var stubBinding: ItemEmptyStateBinding? = null - - override fun onInflateView( - inflater: LayoutInflater, - container: ViewGroup? - ) = FragmentFavouritesBinding.inflate(inflater, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val adapter = FavouritesPagerAdapter(this, this) - viewModel.allCategories.value?.let(::onCategoriesChanged) - binding.pager.adapter = adapter - pagerAdapter = adapter - TabLayoutMediator(binding.tabs, binding.pager, adapter).attach() - actionModeDelegate.addListener(this, viewLifecycleOwner) - addMenuProvider(FavouritesContainerMenuProvider(view.context)) - - viewModel.allCategories.observe(viewLifecycleOwner, ::onCategoriesChanged) - viewModel.onError.observe(viewLifecycleOwner, ::onError) - } - - override fun onDestroyView() { - pagerAdapter = null - stubBinding = null - super.onDestroyView() - } - - override fun onActionModeStarted(mode: ActionMode) { - binding.pager.isUserInputEnabled = false - binding.tabs.setTabsEnabled(false) - } - - override fun onActionModeFinished(mode: ActionMode) { - binding.pager.isUserInputEnabled = true - binding.tabs.setTabsEnabled(true) - } - - override fun onWindowInsetsChanged(insets: Insets) { - binding.tabs.apply { - updatePadding( - left = insets.left, - right = insets.right - ) - } - } - - private fun onCategoriesChanged(categories: List) { - pagerAdapter?.replaceData(categories) - if (categories.isEmpty()) { - binding.pager.isVisible = false - binding.tabs.isVisible = false - showStub() - } else { - binding.pager.isVisible = true - binding.tabs.isVisible = true - (stubBinding?.root ?: binding.stubEmptyState).isVisible = false - } - } - - private fun onError(e: Throwable) { - Snackbar.make(binding.pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show() - } - - override fun onTabLongClick(tabView: View, item: CategoryListModel): Boolean { - /*when (item) { - is CategoryListModel.All -> showAllCategoriesMenu(tabView) - is CategoryListModel.CategoryItem -> showCategoryMenu(tabView, item.category) - }*/ - return true - } - - override fun onClick(v: View) { - when (v.id) { - R.id.button_retry -> startActivity(FavouritesCategoryEditActivity.newIntent(v.context)) - } - } - - override fun onDeleteCategory(category: FavouriteCategory) { - viewModel.deleteCategory(category.id) - } - - private fun TabLayout.setTabsEnabled(enabled: Boolean) { - val tabStrip = getChildAt(0) as? ViewGroup ?: return - for (tab in tabStrip.children) { - tab.isEnabled = enabled - } - } - - private fun showCategoryMenu(tabView: View, category: FavouriteCategory) { - val menu = PopupMenu(tabView.context, tabView) - menu.inflate(R.menu.popup_category) - menu.setOnMenuItemClickListener { - when (it.itemId) { - R.id.action_remove -> editDelegate.deleteCategory(category) - R.id.action_edit -> startActivity( - FavouritesCategoryEditActivity.newIntent( - tabView.context, - category.id - ) - ) - else -> return@setOnMenuItemClickListener false - } - 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 -> startActivity(FavouritesCategoryEditActivity.newIntent(requireContext())) - R.id.action_hide -> viewModel.setAllCategoriesVisible(false) - } - true - } - menu.show() - } - - private fun showStub() { - val stub = stubBinding ?: ItemEmptyStateBinding.bind(binding.stubEmptyState.inflate()) - stub.root.isVisible = true - stub.icon.setImageResource(R.drawable.ic_heart_outline) - stub.textPrimary.setText(R.string.text_empty_holder_primary) - stub.textSecondary.setText(R.string.empty_favourite_categories) - stub.buttonRetry.setText(R.string.add) - stub.buttonRetry.isVisible = true - stub.buttonRetry.setOnClickListener(this) - stubBinding = stub - } - - companion object { - - fun newInstance() = FavouritesContainerFragment() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerMenuProvider.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerMenuProvider.kt deleted file mode 100644 index 869771a0d..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesContainerMenuProvider.kt +++ /dev/null @@ -1,28 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui - -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.FavouriteCategoriesActivity - -class FavouritesContainerMenuProvider( - private val context: Context, -) : 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_categories -> { - context.startActivity(FavouriteCategoriesActivity.newIntent(context)) - true - } - else -> false - } - } -} \ No newline at end of file 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 deleted file mode 100644 index bde316b14..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesPagerAdapter.kt +++ /dev/null @@ -1,70 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui - -import android.annotation.SuppressLint -import android.view.View -import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.AsyncListDiffer -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.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 { - - private val differ = AsyncListDiffer(this, DiffCallback()) - - override fun getItemCount() = differ.currentList.size - - override fun createFragment(position: Int): Fragment { - val item = differ.currentList[position] - return FavouritesListFragment.newInstance(item.category.id) - } - - override fun getItemId(position: Int): Long { - return differ.currentList[position].category.id - } - - override fun containsItem(itemId: Long): Boolean { - return differ.currentList.any { it.category.id == itemId } - } - - override fun onConfigureTab(tab: TabLayout.Tab, position: Int) { - val item = differ.currentList[position] - tab.text = item.category.title - tab.view.tag = item.category.id - tab.view.setOnLongClickListener(this) - } - - fun replaceData(data: List) { - differ.submitList(data) - } - - override fun onLongClick(v: View): Boolean { - val itemId = v.tag as? Long ?: return false - val item = differ.currentList.find { x -> x.category.id == itemId } ?: return false - return longClickListener.onTabLongClick(v, item) - } - - private class DiffCallback : DiffUtil.ItemCallback() { - - override fun areItemsTheSame( - oldItem: CategoryListModel, - newItem: CategoryListModel - ): Boolean { - return oldItem.category.id == newItem.category.id - } - - @SuppressLint("DiffUtilEquals") - override fun areContentsTheSame( - 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 deleted file mode 100644 index 13fca87c9..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/FavouritesTabLongClickListener.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui - -import android.view.View -import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel - -fun interface FavouritesTabLongClickListener { - - 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/CategoriesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesAdapter.kt index cd8418aa6..78ae70f17 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,8 +4,6 @@ import androidx.lifecycle.LifecycleOwner import androidx.recyclerview.widget.DiffUtil import coil.ImageLoader 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.categoryAD import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener @@ -17,7 +15,7 @@ import kotlin.jvm.internal.Intrinsics class CategoriesAdapter( coil: ImageLoader, lifecycleOwner: LifecycleOwner, - onItemClickListener: OnListItemClickListener, + onItemClickListener: FavouriteCategoriesListListener, listListener: ListStateHolderListener, ) : AsyncListDifferDelegationAdapter(DiffCallback()) { @@ -43,7 +41,16 @@ class CategoriesAdapter( } override fun getChangePayload(oldItem: ListModel, newItem: ListModel): Any? { - return super.getChangePayload(oldItem, newItem) + return when { + oldItem is CategoryListModel && newItem is CategoryListModel -> { + if (oldItem.isReorderMode != newItem.isReorderMode) { + Unit + } else { + super.getChangePayload(oldItem, newItem) + } + } + else -> super.getChangePayload(oldItem, newItem) + } } } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt deleted file mode 100644 index cece6607f..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui.categories - -import android.content.Context -import com.google.android.material.dialog.MaterialAlertDialogBuilder -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.core.model.FavouriteCategory -import com.google.android.material.R as materialR - -class CategoriesEditDelegate( - private val context: Context, - private val callback: CategoriesEditCallback -) { - - fun deleteCategory(category: FavouriteCategory) { - MaterialAlertDialogBuilder(context, materialR.style.ThemeOverlay_Material3_MaterialAlertDialog_Centered) - .setMessage(context.getString(R.string.category_delete_confirm, category.title)) - .setTitle(R.string.remove_category) - .setIcon(R.drawable.ic_delete) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(R.string.remove) { _, _ -> - callback.onDeleteCategory(category) - }.create() - .show() - } - - interface CategoriesEditCallback { - - fun onDeleteCategory(category: FavouriteCategory) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesSelectionCallback.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesSelectionCallback.kt new file mode 100644 index 000000000..c6cbd4be7 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesSelectionCallback.kt @@ -0,0 +1,64 @@ +package org.koitharu.kotatsu.favourites.ui.categories + +import android.view.Menu +import android.view.MenuItem +import androidx.appcompat.view.ActionMode +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.ui.list.ListSelectionController +import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity +import com.google.android.material.R as materialR + +class CategoriesSelectionCallback( + private val recyclerView: RecyclerView, + private val viewModel: FavouritesCategoriesViewModel, +) : ListSelectionController.Callback2 { + + override fun onSelectionChanged(controller: ListSelectionController, count: Int) { + recyclerView.invalidateItemDecorations() + } + + override fun onCreateActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean { + mode.menuInflater.inflate(R.menu.mode_category, menu) + return true + } + + override fun onPrepareActionMode(controller: ListSelectionController, mode: ActionMode, menu: Menu): Boolean { + val isOneItem = controller.count == 1 + menu.findItem(R.id.action_edit)?.isVisible = isOneItem + mode.title = controller.count.toString() + return true + } + + override fun onActionItemClicked(controller: ListSelectionController, mode: ActionMode, item: MenuItem): Boolean { + return when (item.itemId) { + R.id.action_edit -> { + val id = controller.peekCheckedIds().singleOrNull() ?: return false + val context = recyclerView.context + val intent = FavouritesCategoryEditActivity.newIntent(context, id) + context.startActivity(intent) + mode.finish() + true + } + R.id.action_remove -> { + confirmDeleteCategories(controller.snapshot(), mode) + true + } + else -> false + } + } + + private fun confirmDeleteCategories(ids: Set, mode: ActionMode) { + val context = recyclerView.context + MaterialAlertDialogBuilder(context, materialR.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.deleteCategories(ids) + mode.finish() + }.show() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesSelectionDecoration.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesSelectionDecoration.kt new file mode 100644 index 000000000..ebeaf648a --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesSelectionDecoration.kt @@ -0,0 +1,57 @@ +package org.koitharu.kotatsu.favourites.ui.categories + +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.graphics.RectF +import android.view.View +import androidx.core.graphics.ColorUtils +import androidx.recyclerview.widget.RecyclerView +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.ui.list.decor.AbstractSelectionItemDecoration +import org.koitharu.kotatsu.favourites.ui.categories.adapter.CategoryListModel +import org.koitharu.kotatsu.utils.ext.getItem +import org.koitharu.kotatsu.utils.ext.getThemeColor +import com.google.android.material.R as materialR + +class CategoriesSelectionDecoration(context: Context) : AbstractSelectionItemDecoration() { + + private val paint = Paint(Paint.ANTI_ALIAS_FLAG) + private val radius = context.resources.getDimension(R.dimen.list_selector_corner) + private val strokeColor = context.getThemeColor(materialR.attr.colorPrimary, Color.RED) + private val fillColor = ColorUtils.setAlphaComponent( + ColorUtils.blendARGB(strokeColor, context.getThemeColor(materialR.attr.colorSurface), 0.8f), + 0x74 + ) + private val padding = context.resources.getDimension(R.dimen.grid_spacing_outer) + + init { + paint.strokeWidth = context.resources.getDimension(R.dimen.selection_stroke_width) + hasForeground = true + hasBackground = false + isIncludeDecorAndMargins = false + } + + override fun getItemId(parent: RecyclerView, child: View): Long { + val holder = parent.getChildViewHolder(child) ?: return RecyclerView.NO_ID + val item = holder.getItem(CategoryListModel::class.java) ?: return RecyclerView.NO_ID + return item.category.id + } + + override fun onDrawForeground( + canvas: Canvas, + parent: RecyclerView, + child: View, + bounds: RectF, + state: RecyclerView.State, + ) { + bounds.inset(padding, padding) + paint.color = fillColor + paint.style = Paint.Style.FILL + canvas.drawRoundRect(bounds, radius, radius, paint) + paint.color = strokeColor + paint.style = Paint.Style.STROKE + canvas.drawRoundRect(bounds, radius, radius, paint) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt index 7b418b44c..c047541d4 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesActivity.kt @@ -4,9 +4,12 @@ import android.app.ActivityOptions import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import android.view.View import android.view.ViewGroup import androidx.core.graphics.Insets +import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.core.view.updatePadding import androidx.recyclerview.widget.ItemTouchHelper @@ -16,7 +19,7 @@ import org.koin.android.ext.android.get import org.koin.androidx.viewmodel.ext.android.viewModel import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseActivity -import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.base.ui.list.ListSelectionController import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.databinding.ActivityCategoriesBinding import org.koitharu.kotatsu.favourites.ui.FavouritesActivity @@ -29,50 +32,78 @@ import org.koitharu.kotatsu.utils.ext.measureHeight class FavouriteCategoriesActivity : BaseActivity(), - OnListItemClickListener, + FavouriteCategoriesListListener, View.OnClickListener, - CategoriesEditDelegate.CategoriesEditCallback, ListStateHolderListener { private val viewModel by viewModel() private lateinit var adapter: CategoriesAdapter - private lateinit var reorderHelper: ItemTouchHelper - private lateinit var editDelegate: CategoriesEditDelegate + private lateinit var selectionController: ListSelectionController + private var reorderHelper: ItemTouchHelper? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(ActivityCategoriesBinding.inflate(layoutInflater)) supportActionBar?.setDisplayHomeAsUpEnabled(true) adapter = CategoriesAdapter(get(), this, this, this) - editDelegate = CategoriesEditDelegate(this, this) + selectionController = ListSelectionController( + activity = this, + decoration = CategoriesSelectionDecoration(this), + registryOwner = this, + callback = CategoriesSelectionCallback(binding.recyclerView, viewModel), + ) + binding.buttonDone.setOnClickListener(this) + selectionController.attachToRecyclerView(binding.recyclerView) binding.recyclerView.setHasFixedSize(true) binding.recyclerView.adapter = adapter binding.fabAdd.setOnClickListener(this) - reorderHelper = ItemTouchHelper(ReorderHelperCallback()) - reorderHelper.attachToRecyclerView(binding.recyclerView) viewModel.detalizedCategories.observe(this, ::onCategoriesChanged) viewModel.onError.observe(this, ::onError) + viewModel.isInReorderMode.observe(this, ::onReorderModeChanged) + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) + menuInflater.inflate(R.menu.opt_categories, menu) + return true + } + + override fun onPrepareOptionsMenu(menu: Menu): Boolean { + menu.findItem(R.id.action_reorder)?.isVisible = !viewModel.isInReorderMode() + return super.onPrepareOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.action_reorder -> { + viewModel.setReorderMode(true) + true + } + else -> super.onOptionsItemSelected(item) + } + } + + override fun onBackPressed() { + if (viewModel.isInReorderMode()) { + viewModel.setReorderMode(false) + } else { + super.onBackPressed() + } } override fun onClick(v: View) { when (v.id) { + R.id.button_done -> viewModel.setReorderMode(false) R.id.fab_add -> startActivity(FavouritesCategoryEditActivity.newIntent(this)) } } override fun onItemClick(item: FavouriteCategory, view: View) { - /*val menu = PopupMenu(view.context, view) - menu.inflate(R.menu.popup_category) - menu.setOnMenuItemClickListener { menuItem -> - when (menuItem.itemId) { - R.id.action_remove -> editDelegate.deleteCategory(item) - R.id.action_edit -> startActivity(FavouritesCategoryEditActivity.newIntent(this, item.id)) - } - true + if (viewModel.isInReorderMode() || selectionController.onItemClick(item.id)) { + return } - menu.show()*/ val intent = FavouritesActivity.newIntent(this, item) val options = ActivityOptions.makeScaleUpAnimation(view, view.width / 2, view.height / 2, view.width, view.height) @@ -80,9 +111,11 @@ class FavouriteCategoriesActivity : } override fun onItemLongClick(item: FavouriteCategory, view: View): Boolean { - val viewHolder = binding.recyclerView.findContainingViewHolder(view) ?: return false - reorderHelper.startDrag(viewHolder) - return true + return !viewModel.isInReorderMode() && selectionController.onItemLongClick(item.id) + } + + override fun onDragHandleTouch(holder: RecyclerView.ViewHolder): Boolean { + return reorderHelper?.startDrag(holder) != null } override fun onRetryClick(error: Throwable) = Unit @@ -111,8 +144,21 @@ class FavouriteCategoriesActivity : .show() } - override fun onDeleteCategory(category: FavouriteCategory) { - viewModel.deleteCategory(category.id) + private fun onReorderModeChanged(isReorderMode: Boolean) { + reorderHelper?.attachToRecyclerView(null) + reorderHelper = if (isReorderMode) { + selectionController.clear() + binding.fabAdd.hide() + ItemTouchHelper(ReorderHelperCallback()).apply { + attachToRecyclerView(binding.recyclerView) + } + } else { + binding.fabAdd.show() + null + } + binding.recyclerView.isNestedScrollingEnabled = !isReorderMode + invalidateOptionsMenu() + binding.buttonDone.isVisible = isReorderMode } private inner class ReorderHelperCallback : ItemTouchHelper.SimpleCallback( diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesListListener.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesListListener.kt new file mode 100644 index 000000000..7819d0112 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouriteCategoriesListListener.kt @@ -0,0 +1,10 @@ +package org.koitharu.kotatsu.favourites.ui.categories + +import androidx.recyclerview.widget.RecyclerView +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.model.FavouriteCategory + +interface FavouriteCategoriesListListener : OnListItemClickListener { + + fun onDragHandleTouch(holder: RecyclerView.ViewHolder): Boolean +} \ No newline at end of file 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 8f727e53d..c0b6a9927 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 @@ -1,9 +1,11 @@ package org.koitharu.kotatsu.favourites.ui.categories +import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine import org.koitharu.kotatsu.base.ui.BaseViewModel import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.favourites.domain.FavouritesRepository @@ -20,6 +22,9 @@ class FavouritesCategoriesViewModel( ) : BaseViewModel() { private var reorderJob: Job? = null + private val isReorder = MutableStateFlow(false) + + val isInReorderMode = isReorder.asLiveData(viewModelScope.coroutineContext) val allCategories = repository.observeCategories() .mapItems { @@ -27,19 +32,23 @@ class FavouritesCategoriesViewModel( mangaCount = 0, covers = listOf(), category = it, + isReorderMode = false, ) }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList()) - val detalizedCategories = repository.observeCategoriesWithDetails() - .map { - it.map { (category, covers) -> - CategoryListModel( - mangaCount = covers.size, - covers = covers.take(3), - category = category, - ) - } - }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) + val detalizedCategories = combine( + repository.observeCategoriesWithDetails(), + isReorder, + ) { list, reordering -> + list.map { (category, covers) -> + CategoryListModel( + mangaCount = covers.size, + covers = covers.take(3), + category = category, + isReorderMode = reordering, + ) + } + }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState)) fun deleteCategory(id: Long) { launchJob { @@ -47,10 +56,22 @@ class FavouritesCategoriesViewModel( } } + fun deleteCategories(ids: Set) { + launchJob { + repository.removeCategories(ids) + } + } + fun setAllCategoriesVisible(isVisible: Boolean) { settings.isAllFavouritesVisible = isVisible } + fun isInReorderMode(): Boolean = isReorder.value + + fun setReorderMode(isReorderMode: Boolean) { + isReorder.value = isReorderMode + } + fun reorderCategories(oldPos: Int, newPos: Int) { val prevJob = reorderJob reorderJob = launchJob(Dispatchers.Default) { diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt index 6f9de0731..5ca53ad84 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/adapter/CategoryAD.kt @@ -1,8 +1,14 @@ package org.koitharu.kotatsu.favourites.ui.categories.adapter +import android.content.res.ColorStateList +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.view.MotionEvent import android.view.View -import android.view.View.OnClickListener -import android.view.View.OnLongClickListener +import android.view.View.* +import androidx.core.graphics.ColorUtils +import androidx.core.view.isVisible +import androidx.core.widget.ImageViewCompat import androidx.lifecycle.LifecycleOwner import coil.ImageLoader import coil.request.Disposable @@ -10,32 +16,50 @@ import coil.size.Scale import coil.util.CoilUtils import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.databinding.ItemCategoryBinding +import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesListListener import org.koitharu.kotatsu.list.ui.model.ListModel +import org.koitharu.kotatsu.utils.ext.animatorDurationScale import org.koitharu.kotatsu.utils.ext.enqueueWith +import org.koitharu.kotatsu.utils.ext.getThemeColor import org.koitharu.kotatsu.utils.ext.newImageRequest fun categoryAD( coil: ImageLoader, lifecycleOwner: LifecycleOwner, - clickListener: OnListItemClickListener + clickListener: FavouriteCategoriesListListener, ) = adapterDelegateViewBinding( { inflater, parent -> ItemCategoryBinding.inflate(inflater, parent, false) } ) { - val eventListener = object : OnClickListener, OnLongClickListener { + val eventListener = object : OnClickListener, OnLongClickListener, OnTouchListener { override fun onClick(v: View) = clickListener.onItemClick(item.category, v) override fun onLongClick(v: View) = clickListener.onItemLongClick(item.category, v) + override fun onTouch(v: View?, event: MotionEvent): Boolean = item.isReorderMode && + event.actionMasked == MotionEvent.ACTION_DOWN && + clickListener.onDragHandleTouch(this@adapterDelegateViewBinding) } + val backgroundColor = context.getThemeColor(android.R.attr.colorBackground) + ImageViewCompat.setImageTintList( + binding.imageViewCover3, + ColorStateList.valueOf(ColorUtils.setAlphaComponent(backgroundColor, 153)) + ) + ImageViewCompat.setImageTintList( + binding.imageViewCover2, + ColorStateList.valueOf(ColorUtils.setAlphaComponent(backgroundColor, 76)) + ) + val fallback = ColorDrawable(Color.TRANSPARENT) val coverViews = arrayOf(binding.imageViewCover1, binding.imageViewCover2, binding.imageViewCover3) val imageRequests = arrayOfNulls(coverViews.size) + val crossFadeDuration = (context.resources.getInteger(R.integer.config_defaultAnimTime) * + context.animatorDurationScale).toInt() itemView.setOnClickListener(eventListener) itemView.setOnLongClickListener(eventListener) + itemView.setOnTouchListener(eventListener) bind { imageRequests.forEach { it?.dispose() } + binding.imageViewHandle.isVisible = item.isReorderMode binding.textViewTitle.text = item.category.title binding.textViewSubtitle.text = context.resources.getQuantityString( R.plurals.items, @@ -45,7 +69,8 @@ fun categoryAD( repeat(coverViews.size) { i -> imageRequests[i] = coverViews[i].newImageRequest(item.covers.getOrNull(i)) .placeholder(R.drawable.ic_placeholder) - .fallback(null) + .crossfade(crossFadeDuration * (i + 1)) + .fallback(fallback) .error(R.drawable.ic_placeholder) .scale(Scale.FILL) .allowRgb565(true) 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 index 352ef976a..abc5e6314 100644 --- 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 @@ -7,6 +7,7 @@ class CategoryListModel( val mangaCount: Int, val covers: List, val category: FavouriteCategory, + val isReorderMode: Boolean, ) : ListModel { override fun equals(other: Any?): Boolean { @@ -16,6 +17,7 @@ class CategoryListModel( other as CategoryListModel if (mangaCount != other.mangaCount) return false + if (isReorderMode != other.isReorderMode) return false if (covers != other.covers) return false if (category.id != other.category.id) return false if (category.title != other.category.title) return false @@ -26,6 +28,7 @@ class CategoryListModel( override fun hashCode(): Int { var result = mangaCount + result = 31 * result + isReorderMode.hashCode() result = 31 * result + covers.hashCode() result = 31 * result + category.id.hashCode() result = 31 * result + category.title.hashCode() diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt index f13cce9a7..f8b0238fa 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesBottomSheet.kt @@ -11,10 +11,8 @@ import org.koin.core.parameter.parametersOf import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseBottomSheet import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener -import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga import org.koitharu.kotatsu.databinding.DialogFavoriteCategoriesBinding -import org.koitharu.kotatsu.favourites.ui.categories.CategoriesEditDelegate import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity import org.koitharu.kotatsu.favourites.ui.categories.select.adapter.MangaCategoriesAdapter import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem @@ -25,7 +23,6 @@ import org.koitharu.kotatsu.utils.ext.withArgs class FavouriteCategoriesBottomSheet : BaseBottomSheet(), OnListItemClickListener, - CategoriesEditDelegate.CategoriesEditCallback, View.OnClickListener { private val viewModel by viewModel { @@ -66,8 +63,6 @@ class FavouriteCategoriesBottomSheet : viewModel.setChecked(item.id, !item.isChecked) } - override fun onDeleteCategory(category: FavouriteCategory) = Unit - private fun onContentChanged(categories: List) { adapter?.items = categories } diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt index 9fd4542ec..147cb515d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/util/ReadingProgressDrawable.kt @@ -8,7 +8,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.core.graphics.ColorUtils import org.koitharu.kotatsu.R import org.koitharu.kotatsu.history.domain.PROGRESS_NONE -import kotlin.math.roundToInt +import org.koitharu.kotatsu.utils.ext.scale class ReadingProgressDrawable( context: Context, @@ -105,7 +105,7 @@ class ReadingProgressDrawable( if (hasText) { if (checkDrawable != null && progress >= 1f - Math.ulp(progress)) { tempRect.set(bounds) - tempRect *= 0.6 + tempRect.scale(0.6) checkDrawable.bounds = tempRect checkDrawable.draw(canvas) } else { @@ -139,13 +139,4 @@ class ReadingProgressDrawable( paint.getTextBounds(text, 0, text.length, tempRect) return testTextSize * width / tempRect.width() } - - private operator fun Rect.timesAssign(factor: Double) { - val newWidth = (width() * factor).roundToInt() - val newHeight = (height() * factor).roundToInt() - inset( - (width() - newWidth) / 2, - (height() - newHeight) / 2, - ) - } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index dfd3af976..3afceafd6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -133,8 +133,9 @@ class ReaderActivity : } override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.opt_reader_top, menu) - return super.onCreateOptionsMenu(menu) + return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt index 91c8a34f3..b3695389d 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/SettingsActivity.kt @@ -62,8 +62,9 @@ class SettingsActivity : } override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) menuInflater.inflate(R.menu.opt_settings, menu) - return super.onCreateOptionsMenu(menu) + return true } override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/GraphicsExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/GraphicsExt.kt new file mode 100644 index 000000000..94dc692a3 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/GraphicsExt.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.utils.ext + +import android.graphics.Rect +import kotlin.math.roundToInt + +fun Rect.scale(factor: Double) { + val newWidth = (width() * factor).roundToInt() + val newHeight = (height() * factor).roundToInt() + inset( + (width() - newWidth) / 2, + (height() - newHeight) / 2, + ) +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_edit.xml b/app/src/main/res/drawable/ic_edit.xml new file mode 100644 index 000000000..fa3d244b5 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_reorder.xml b/app/src/main/res/drawable/ic_reorder.xml new file mode 100644 index 000000000..3ebd02732 --- /dev/null +++ b/app/src/main/res/drawable/ic_reorder.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_category.xml b/app/src/main/res/layout/item_category.xml index 3565f314d..939129742 100644 --- a/app/src/main/res/layout/item_category.xml +++ b/app/src/main/res/layout/item_category.xml @@ -6,9 +6,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/list_selector" - android:paddingVertical="12dp" + android:minHeight="98dp" android:paddingStart="?android:listPreferredItemPaddingStart" - android:paddingEnd="?listPreferredItemPaddingEnd"> + tools:ignore="RtlSymmetry"> + app:tintMode="src_atop" + tools:src="@tools:sample/backgrounds/scenic" + tools:tint="#99FFFFFF" /> + app:tintMode="src_atop" + tools:src="@tools:sample/backgrounds/scenic" + tools:tint="#4DFFFFFF" /> + + \ No newline at end of file diff --git a/app/src/main/res/menu/mode_category.xml b/app/src/main/res/menu/mode_category.xml new file mode 100644 index 000000000..2877cfd75 --- /dev/null +++ b/app/src/main/res/menu/mode_category.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/opt_favourites.xml b/app/src/main/res/menu/opt_categories.xml similarity index 53% rename from app/src/main/res/menu/opt_favourites.xml rename to app/src/main/res/menu/opt_categories.xml index 627c0bf85..1323bedf1 100644 --- a/app/src/main/res/menu/opt_favourites.xml +++ b/app/src/main/res/menu/opt_categories.xml @@ -4,9 +4,9 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> + android:id="@+id/action_reorder" + android:icon="@drawable/ic_reorder" + android:title="@string/reorder" + app:showAsAction="ifRoom" /> \ No newline at end of file diff --git a/app/src/main/res/menu/popup_category.xml b/app/src/main/res/menu/popup_category.xml deleted file mode 100644 index 50c1313be..000000000 --- a/app/src/main/res/menu/popup_category.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/popup_category_all.xml b/app/src/main/res/menu/popup_category_all.xml deleted file mode 100644 index 60b3bc3bd..000000000 --- a/app/src/main/res/menu/popup_category_all.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db37a28b1..ff24e64c0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -330,4 +330,6 @@ No manga sources Enable manga sources to read manga online Random + Are you sure you want to delete the selected favorite categories?\nAll manga in it will be lost and this cannot be undone. + Reorder \ No newline at end of file