Edit favourite category activity
This commit is contained in:
@@ -4,6 +4,7 @@ import org.koin.androidx.viewmodel.dsl.viewModel
|
||||
import org.koin.dsl.module
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditViewModel
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.MangaCategoriesViewModel
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListViewModel
|
||||
|
||||
@@ -19,4 +20,5 @@ val favouritesModule
|
||||
viewModel { manga ->
|
||||
MangaCategoriesViewModel(manga.get(), get())
|
||||
}
|
||||
viewModel { params -> FavouritesCategoryEditViewModel(params[0], get(), get()) }
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import kotlinx.coroutines.flow.Flow
|
||||
@Dao
|
||||
abstract class FavouriteCategoriesDao {
|
||||
|
||||
@Query("SELECT * FROM favourite_categories WHERE category_id = :id")
|
||||
abstract suspend fun find(id: Int): FavouriteCategoryEntity
|
||||
|
||||
@Query("SELECT * FROM favourite_categories ORDER BY sort_key")
|
||||
abstract suspend fun findAll(): List<FavouriteCategoryEntity>
|
||||
|
||||
@@ -27,6 +30,9 @@ abstract class FavouriteCategoriesDao {
|
||||
@Query("UPDATE favourite_categories SET title = :title WHERE category_id = :id")
|
||||
abstract suspend fun updateTitle(id: Long, title: String)
|
||||
|
||||
@Query("UPDATE favourite_categories SET title = :title, `order` = :order, `track` = :tracker WHERE category_id = :id")
|
||||
abstract suspend fun update(id: Long, title: String, order: String, tracker: Boolean)
|
||||
|
||||
@Query("UPDATE favourite_categories SET `order` = :order WHERE category_id = :id")
|
||||
abstract suspend fun updateOrder(id: Long, order: String)
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ class FavouritesRepository(
|
||||
}.distinctUntilChanged()
|
||||
}
|
||||
|
||||
fun observeCategory(id: Long): Flow<FavouriteCategory> {
|
||||
return db.favouriteCategoriesDao.observe(id)
|
||||
.map { it.toFavouriteCategory() }
|
||||
}
|
||||
|
||||
fun observeCategories(mangaId: Long): Flow<List<FavouriteCategory>> {
|
||||
return db.favouritesDao.observe(mangaId).map { entity ->
|
||||
entity?.categories?.map { it.toFavouriteCategory() }.orEmpty()
|
||||
@@ -62,6 +67,29 @@ class FavouritesRepository(
|
||||
return db.favouritesDao.observeIds(mangaId).map { it.toSet() }
|
||||
}
|
||||
|
||||
suspend fun getCategory(id: Long): FavouriteCategory {
|
||||
return db.favouriteCategoriesDao.find(id.toInt()).toFavouriteCategory()
|
||||
}
|
||||
|
||||
suspend fun createCategory(title: String, sortOrder: SortOrder, isTrackerEnabled: Boolean): FavouriteCategory {
|
||||
val entity = FavouriteCategoryEntity(
|
||||
title = title,
|
||||
createdAt = System.currentTimeMillis(),
|
||||
sortKey = db.favouriteCategoriesDao.getNextSortKey(),
|
||||
categoryId = 0,
|
||||
order = sortOrder.name,
|
||||
track = isTrackerEnabled,
|
||||
)
|
||||
val id = db.favouriteCategoriesDao.insert(entity)
|
||||
val category = entity.toFavouriteCategory(id)
|
||||
channels.createChannel(category)
|
||||
return category
|
||||
}
|
||||
|
||||
suspend fun updateCategory(id: Long, title: String, sortOrder: SortOrder, isTrackerEnabled: Boolean) {
|
||||
db.favouriteCategoriesDao.update(id, title, sortOrder.name, isTrackerEnabled)
|
||||
}
|
||||
|
||||
suspend fun addCategory(title: String): FavouriteCategory {
|
||||
val entity = FavouriteCategoryEntity(
|
||||
title = title,
|
||||
|
||||
@@ -16,12 +16,12 @@ 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.core.ui.titleRes
|
||||
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.favourites.ui.categories.edit.FavouritesCategoryEditActivity
|
||||
import org.koitharu.kotatsu.main.ui.AppBarOwner
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.measureHeight
|
||||
@@ -134,28 +134,6 @@ class FavouritesContainerFragment :
|
||||
viewModel.deleteCategory(category.id)
|
||||
}
|
||||
|
||||
override fun onRenameCategory(category: FavouriteCategory, newName: String) {
|
||||
viewModel.renameCategory(category.id, newName)
|
||||
}
|
||||
|
||||
override fun onCreateCategory(name: String) {
|
||||
viewModel.createCategory(name)
|
||||
}
|
||||
|
||||
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()) {
|
||||
val menuItem = submenu.add(R.id.group_order, Menu.NONE, i, item.titleRes)
|
||||
menuItem.isCheckable = true
|
||||
menuItem.isChecked = item == category.order
|
||||
}
|
||||
submenu.setGroupCheckable(R.id.group_order, true, true)
|
||||
menu.findItem(R.id.action_tracking)?.run {
|
||||
isVisible = viewModel.isFavouritesTrackerEnabled
|
||||
isChecked = category.isTrackingEnabled
|
||||
}
|
||||
}
|
||||
|
||||
private fun TabLayout.setTabsEnabled(enabled: Boolean) {
|
||||
val tabStrip = getChildAt(0) as? ViewGroup ?: return
|
||||
for (tab in tabStrip.children) {
|
||||
@@ -166,19 +144,11 @@ 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_tracking -> viewModel.setCategoryTracking(category.id, !category.isTrackingEnabled)
|
||||
R.id.action_order -> return@setOnMenuItemClickListener false
|
||||
else -> {
|
||||
val order = CategoriesActivity.SORT_ORDERS.getOrNull(it.order)
|
||||
?: return@setOnMenuItemClickListener false
|
||||
viewModel.setCategoryOrder(category.id, order)
|
||||
}
|
||||
R.id.action_edit -> FavouritesCategoryEditActivity.newIntent(tabView.context, category.id)
|
||||
else -> return@setOnMenuItemClickListener false
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -190,7 +160,7 @@ class FavouritesContainerFragment :
|
||||
menu.inflate(R.menu.popup_category_all)
|
||||
menu.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_create -> editDelegate.createCategory()
|
||||
R.id.action_create -> FavouritesCategoryEditActivity.newIntent(requireContext())
|
||||
R.id.action_hide -> viewModel.setAllCategoriesVisible(false)
|
||||
}
|
||||
true
|
||||
|
||||
@@ -3,7 +3,6 @@ package org.koitharu.kotatsu.favourites.ui.categories
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
@@ -19,9 +18,9 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
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.favourites.ui.categories.edit.FavouritesCategoryEditActivity
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.measureHeight
|
||||
@@ -57,24 +56,17 @@ class CategoriesActivity :
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.fab_add -> editDelegate.createCategory()
|
||||
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)
|
||||
prepareCategoryMenu(menu.menu, item)
|
||||
menu.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.action_remove -> editDelegate.deleteCategory(item)
|
||||
R.id.action_rename -> editDelegate.renameCategory(item)
|
||||
R.id.action_tracking -> viewModel.setCategoryTracking(item.id, !item.isTrackingEnabled)
|
||||
R.id.action_order -> return@setOnMenuItemClickListener false
|
||||
else -> {
|
||||
val order = SORT_ORDERS.getOrNull(menuItem.order) ?: return@setOnMenuItemClickListener false
|
||||
viewModel.setCategoryOrder(item.id, order)
|
||||
}
|
||||
R.id.action_edit -> startActivity(FavouritesCategoryEditActivity.newIntent(this, item.id))
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -118,33 +110,6 @@ class CategoriesActivity :
|
||||
viewModel.deleteCategory(category.id)
|
||||
}
|
||||
|
||||
override fun onRenameCategory(category: FavouriteCategory, newName: String) {
|
||||
viewModel.renameCategory(category.id, newName)
|
||||
}
|
||||
|
||||
override fun onCreateCategory(name: String) {
|
||||
viewModel.createCategory(name)
|
||||
}
|
||||
|
||||
private fun prepareCategoryMenu(menu: Menu, category: FavouriteCategory) {
|
||||
val submenu = menu.findItem(R.id.action_order)?.subMenu ?: return
|
||||
for ((i, item) in SORT_ORDERS.withIndex()) {
|
||||
val menuItem = submenu.add(
|
||||
R.id.group_order,
|
||||
Menu.NONE,
|
||||
i,
|
||||
item.titleRes
|
||||
)
|
||||
menuItem.isCheckable = true
|
||||
menuItem.isChecked = item == category.order
|
||||
}
|
||||
submenu.setGroupCheckable(R.id.group_order, true, true)
|
||||
menu.findItem(R.id.action_tracking)?.run {
|
||||
isVisible = viewModel.isFavouritesTrackerEnabled
|
||||
isChecked = category.isTrackingEnabled
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ReorderHelperCallback : ItemTouchHelper.SimpleCallback(
|
||||
ItemTouchHelper.DOWN or ItemTouchHelper.UP, 0
|
||||
) {
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import android.content.Context
|
||||
import android.text.InputType
|
||||
import android.widget.Toast
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.dialog.TextInputDialog
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
|
||||
private const val MAX_TITLE_LENGTH = 24
|
||||
|
||||
class CategoriesEditDelegate(
|
||||
private val context: Context,
|
||||
private val callback: CategoriesEditCallback
|
||||
@@ -26,49 +21,8 @@ class CategoriesEditDelegate(
|
||||
.show()
|
||||
}
|
||||
|
||||
fun renameCategory(category: FavouriteCategory) {
|
||||
TextInputDialog.Builder(context)
|
||||
.setTitle(R.string.rename)
|
||||
.setText(category.title)
|
||||
.setHint(R.string.enter_category_name)
|
||||
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
||||
.setNegativeButton(android.R.string.cancel)
|
||||
.setMaxLength(MAX_TITLE_LENGTH, false)
|
||||
.setPositiveButton(R.string.rename) { _, name ->
|
||||
val trimmed = name.trim()
|
||||
if (trimmed.isEmpty()) {
|
||||
Toast.makeText(context, R.string.error_empty_name, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
callback.onRenameCategory(category, name)
|
||||
}
|
||||
}.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
fun createCategory() {
|
||||
TextInputDialog.Builder(context)
|
||||
.setTitle(R.string.add_new_category)
|
||||
.setHint(R.string.enter_category_name)
|
||||
.setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
|
||||
.setNegativeButton(android.R.string.cancel)
|
||||
.setMaxLength(MAX_TITLE_LENGTH, false)
|
||||
.setPositiveButton(R.string.add) { _, name ->
|
||||
val trimmed = name.trim()
|
||||
if (trimmed.isEmpty()) {
|
||||
Toast.makeText(context, R.string.error_empty_name, Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
callback.onCreateCategory(trimmed)
|
||||
}
|
||||
}.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
interface CategoriesEditCallback {
|
||||
|
||||
fun onDeleteCategory(category: FavouriteCategory)
|
||||
|
||||
fun onRenameCategory(category: FavouriteCategory, newName: String)
|
||||
|
||||
fun onCreateCategory(name: String)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import java.util.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
@@ -10,8 +9,8 @@ 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,
|
||||
@@ -34,39 +33,12 @@ class FavouritesCategoriesViewModel(
|
||||
mapCategories(list, showAll, showAll)
|
||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||
|
||||
val isFavouritesTrackerEnabled: Boolean
|
||||
get() = settings.isTrackerEnabled && AppSettings.TRACK_FAVOURITES in settings.trackSources
|
||||
|
||||
fun createCategory(name: String) {
|
||||
launchJob {
|
||||
repository.addCategory(name)
|
||||
}
|
||||
}
|
||||
|
||||
fun renameCategory(id: Long, name: String) {
|
||||
launchJob {
|
||||
repository.renameCategory(id, name)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCategory(id: Long) {
|
||||
launchJob {
|
||||
repository.removeCategory(id)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCategoryOrder(id: Long, order: SortOrder) {
|
||||
launchJob {
|
||||
repository.setCategoryOrder(id, order)
|
||||
}
|
||||
}
|
||||
|
||||
fun setCategoryTracking(id: Long, isEnabled: Boolean) {
|
||||
launchJob {
|
||||
repository.setCategoryTracking(id, isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun setAllCategoriesVisible(isVisible: Boolean) {
|
||||
settings.isAllFavouritesVisible = isVisible
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.edit
|
||||
|
||||
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.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updatePadding
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.ui.titleRes
|
||||
import org.koitharu.kotatsu.databinding.ActivityCategoryEditBinding
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
|
||||
class FavouritesCategoryEditActivity : BaseActivity<ActivityCategoryEditBinding>(), AdapterView.OnItemClickListener {
|
||||
|
||||
private val viewModel by viewModel<FavouritesCategoryEditViewModel> {
|
||||
parametersOf(intent.getLongExtra(EXTRA_ID, NO_ID))
|
||||
}
|
||||
private var selectedSortOrder: SortOrder? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivityCategoryEditBinding.inflate(layoutInflater))
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setHomeAsUpIndicator(com.google.android.material.R.drawable.abc_ic_clear_material)
|
||||
}
|
||||
initSortSpinner()
|
||||
|
||||
viewModel.onSaved.observe(this) { finishAfterTransition() }
|
||||
viewModel.category.observe(this, ::onCategoryChanged)
|
||||
viewModel.isLoading.observe(this, ::onLoadingStateChanged)
|
||||
viewModel.onError.observe(this, ::onError)
|
||||
viewModel.isTrackerEnabled.observe(this) {
|
||||
binding.switchTracker.isVisible = it
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putSerializable(KEY_SORT_ORDER, selectedSortOrder)
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
super.onRestoreInstanceState(savedInstanceState)
|
||||
val order = savedInstanceState.getSerializable(KEY_SORT_ORDER)
|
||||
if (order != null && order is SortOrder) {
|
||||
selectedSortOrder = order
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.opt_config, menu)
|
||||
menu.findItem(R.id.action_done)?.setTitle(R.string.save)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
R.id.action_done -> {
|
||||
viewModel.save(
|
||||
title = binding.editName.text?.toString().orEmpty(),
|
||||
sortOrder = getSelectedSortOrder(),
|
||||
isTrackerEnabled = binding.switchTracker.isChecked,
|
||||
)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
binding.scrollView.updatePadding(
|
||||
left = insets.left,
|
||||
right = insets.right,
|
||||
bottom = insets.bottom,
|
||||
)
|
||||
binding.toolbar.updatePadding(
|
||||
top = insets.top,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
selectedSortOrder = CategoriesActivity.SORT_ORDERS.getOrNull(position)
|
||||
}
|
||||
|
||||
private fun onCategoryChanged(category: FavouriteCategory?) {
|
||||
setTitle(if (category == null) R.string.create_category else R.string.edit_category)
|
||||
if (selectedSortOrder != null) {
|
||||
return
|
||||
}
|
||||
binding.editName.setText(category?.title)
|
||||
selectedSortOrder = category?.order
|
||||
val sortText = getString((category?.order ?: SortOrder.NEWEST).titleRes)
|
||||
binding.editSort.setText(sortText, false)
|
||||
binding.switchTracker.isChecked = category?.isTrackingEnabled ?: true
|
||||
}
|
||||
|
||||
private fun onError(e: Throwable) {
|
||||
binding.textViewError.text = e.getDisplayMessage(resources)
|
||||
binding.textViewError.isVisible = true
|
||||
}
|
||||
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
binding.editSort.isEnabled = !isLoading
|
||||
binding.editName.isEnabled = !isLoading
|
||||
binding.switchTracker.isEnabled = !isLoading
|
||||
if (isLoading) {
|
||||
binding.textViewError.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun initSortSpinner() {
|
||||
val entries = CategoriesActivity.SORT_ORDERS.map { getString(it.titleRes) }
|
||||
val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, entries)
|
||||
binding.editSort.setAdapter(adapter)
|
||||
binding.editSort.onItemClickListener = this
|
||||
}
|
||||
|
||||
private fun getSelectedSortOrder(): SortOrder {
|
||||
selectedSortOrder?.let { return it }
|
||||
val entries = CategoriesActivity.SORT_ORDERS.map { getString(it.titleRes) }
|
||||
val index = entries.indexOf(binding.editSort.text.toString())
|
||||
return CategoriesActivity.SORT_ORDERS.getOrNull(index) ?: SortOrder.NEWEST
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_ID = "id"
|
||||
private const val KEY_SORT_ORDER = "sort"
|
||||
private const val NO_ID = -1L
|
||||
|
||||
fun newIntent(context: Context, id: Long = NO_ID): Intent {
|
||||
return Intent(context, FavouritesCategoryEditActivity::class.java)
|
||||
.putExtra(EXTRA_ID, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.edit
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.liveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
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.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||
|
||||
private const val NO_ID = -1L
|
||||
|
||||
class FavouritesCategoryEditViewModel(
|
||||
private val categoryId: Long,
|
||||
private val repository: FavouritesRepository,
|
||||
private val settings: AppSettings,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val onSaved = SingleLiveEvent<Unit>()
|
||||
val category = MutableLiveData<FavouriteCategory?>()
|
||||
|
||||
val isTrackerEnabled = liveData(viewModelScope.coroutineContext + Dispatchers.Default) {
|
||||
emit(settings.isTrackerEnabled && AppSettings.TRACK_FAVOURITES in settings.trackSources)
|
||||
}
|
||||
|
||||
init {
|
||||
launchLoadingJob {
|
||||
category.value = if (categoryId != NO_ID) {
|
||||
repository.getCategory(categoryId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun save(
|
||||
title: String,
|
||||
sortOrder: SortOrder,
|
||||
isTrackerEnabled: Boolean,
|
||||
) {
|
||||
launchLoadingJob {
|
||||
if (categoryId == NO_ID) {
|
||||
repository.createCategory(title, sortOrder, isTrackerEnabled)
|
||||
} else {
|
||||
repository.updateCategory(categoryId, title, sortOrder, isTrackerEnabled)
|
||||
}
|
||||
onSaved.call(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ 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
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
@@ -34,9 +35,6 @@ class FavouriteCategoriesDialog :
|
||||
}
|
||||
|
||||
private var adapter: MangaCategoriesAdapter? = null
|
||||
private val editDelegate by lazy(LazyThreadSafetyMode.NONE) {
|
||||
CategoriesEditDelegate(requireContext(), this@FavouriteCategoriesDialog)
|
||||
}
|
||||
|
||||
override fun onInflateView(
|
||||
inflater: LayoutInflater,
|
||||
@@ -61,7 +59,7 @@ class FavouriteCategoriesDialog :
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_create -> {
|
||||
editDelegate.createCategory()
|
||||
FavouritesCategoryEditActivity.newIntent(requireContext())
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
@@ -74,12 +72,6 @@ class FavouriteCategoriesDialog :
|
||||
|
||||
override fun onDeleteCategory(category: FavouriteCategory) = Unit
|
||||
|
||||
override fun onRenameCategory(category: FavouriteCategory, newName: String) = Unit
|
||||
|
||||
override fun onCreateCategory(name: String) {
|
||||
viewModel.createCategory(name)
|
||||
}
|
||||
|
||||
private fun onContentChanged(categories: List<MangaCategoryItem>) {
|
||||
adapter?.items = categories
|
||||
}
|
||||
|
||||
@@ -38,12 +38,6 @@ class MangaCategoriesViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun createCategory(name: String) {
|
||||
launchJob(Dispatchers.Default) {
|
||||
favouritesRepository.addCategory(name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeCategoriesIds() = if (manga.size == 1) {
|
||||
// Fast path
|
||||
favouritesRepository.observeCategoriesIds(manga[0].id)
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.list
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.core.view.iterator
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.titleRes
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity
|
||||
import org.koitharu.kotatsu.list.ui.MangaListFragment
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
@@ -17,12 +23,54 @@ class FavouritesListFragment : MangaListFragment() {
|
||||
}
|
||||
|
||||
private val categoryId: Long
|
||||
get() = arguments?.getLong(ARG_CATEGORY_ID) ?: 0L
|
||||
get() = arguments?.getLong(ARG_CATEGORY_ID) ?: NO_ID
|
||||
|
||||
override val isSwipeRefreshEnabled = false
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
viewModel.sortOrder.observe(viewLifecycleOwner) { activity?.invalidateOptionsMenu() }
|
||||
}
|
||||
|
||||
override fun onScrolledToEnd() = Unit
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
if (categoryId != NO_ID) {
|
||||
inflater.inflate(R.menu.opt_favourites_list, menu)
|
||||
menu.findItem(R.id.action_order)?.subMenu?.let { submenu ->
|
||||
for ((i, item) in CategoriesActivity.SORT_ORDERS.withIndex()) {
|
||||
val menuItem = submenu.add(R.id.group_order, Menu.NONE, i, item.titleRes)
|
||||
menuItem.isCheckable = true
|
||||
}
|
||||
submenu.setGroupCheckable(R.id.group_order, true, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
menu.findItem(R.id.action_order)?.subMenu?.let { submenu ->
|
||||
val selectedOrder = viewModel.sortOrder.value
|
||||
for (item in submenu) {
|
||||
val order = CategoriesActivity.SORT_ORDERS.getOrNull(item.order)
|
||||
item.isChecked = order == selectedOrder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when {
|
||||
item.itemId == R.id.action_order -> false
|
||||
item.groupId == R.id.group_order -> {
|
||||
val order = CategoriesActivity.SORT_ORDERS.getOrNull(item.order) ?: return false
|
||||
viewModel.setSortOrder(order)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.menuInflater.inflate(R.menu.mode_favourites, menu)
|
||||
return super.onCreateActionMode(mode, menu)
|
||||
@@ -48,6 +96,7 @@ class FavouritesListFragment : MangaListFragment() {
|
||||
|
||||
companion object {
|
||||
|
||||
const val NO_ID = 0L
|
||||
private const val ARG_CATEGORY_ID = "category_id"
|
||||
|
||||
fun newInstance(categoryId: Long) = FavouritesListFragment().withArgs(1) {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.list
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.list.FavouritesListFragment.Companion.NO_ID
|
||||
import org.koitharu.kotatsu.list.domain.CountersProvider
|
||||
import org.koitharu.kotatsu.list.ui.MangaListViewModel
|
||||
import org.koitharu.kotatsu.list.ui.model.EmptyState
|
||||
@@ -24,8 +28,16 @@ class FavouritesListViewModel(
|
||||
settings: AppSettings,
|
||||
) : MangaListViewModel(settings), CountersProvider {
|
||||
|
||||
var sortOrder: LiveData<SortOrder> = if (categoryId == NO_ID) {
|
||||
MutableLiveData(null)
|
||||
} else {
|
||||
repository.observeCategory(categoryId)
|
||||
.map { it.order }
|
||||
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||
}
|
||||
|
||||
override val content = combine(
|
||||
if (categoryId == 0L) {
|
||||
if (categoryId == NO_ID) {
|
||||
repository.observeAll(SortOrder.NEWEST)
|
||||
} else {
|
||||
repository.observeAll(categoryId)
|
||||
@@ -37,7 +49,7 @@ class FavouritesListViewModel(
|
||||
EmptyState(
|
||||
icon = R.drawable.ic_heart_outline,
|
||||
textPrimary = R.string.text_empty_holder_primary,
|
||||
textSecondary = if (categoryId == 0L) {
|
||||
textSecondary = if (categoryId == NO_ID) {
|
||||
R.string.you_have_not_favourites_yet
|
||||
} else {
|
||||
R.string.favourites_category_empty
|
||||
@@ -60,7 +72,7 @@ class FavouritesListViewModel(
|
||||
return
|
||||
}
|
||||
launchJob {
|
||||
if (categoryId == 0L) {
|
||||
if (categoryId == NO_ID) {
|
||||
repository.removeFromFavourites(ids)
|
||||
} else {
|
||||
repository.removeFromCategory(categoryId, ids)
|
||||
@@ -68,6 +80,15 @@ class FavouritesListViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
fun setSortOrder(order: SortOrder) {
|
||||
if (categoryId == NO_ID) {
|
||||
return
|
||||
}
|
||||
launchJob {
|
||||
repository.setCategoryOrder(categoryId, order)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getCounter(mangaId: Long): Int {
|
||||
return trackingRepository.getNewChaptersCount(mangaId)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user