diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouriteCategoriesDao.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouriteCategoriesDao.kt index 436dc12ea..9a0e4ed3f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouriteCategoriesDao.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouriteCategoriesDao.kt @@ -13,7 +13,7 @@ abstract class FavouriteCategoriesDao { abstract fun observeAll(): Flow> @Query("SELECT * FROM favourite_categories WHERE category_id = :id") - abstract fun observe(id: Long): Flow + abstract fun observe(id: Long): Flow @Insert(onConflict = OnConflictStrategy.ABORT) abstract suspend fun insert(category: FavouriteCategoryEntity): Long 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 731d7ff5e..026fec18b 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 @@ -1,10 +1,7 @@ package org.koitharu.kotatsu.favourites.domain import androidx.room.withTransaction -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.map +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 @@ -48,6 +45,11 @@ class FavouritesRepository(private val db: MangaDatabase) { }.distinctUntilChanged() } + fun observeCategory(id: Long): Flow { + return db.favouriteCategoriesDao.observe(id) + .map { it?.toFavouriteCategory() } + } + fun observeCategories(mangaId: Long): Flow> { return db.favouritesDao.observe(mangaId).map { entity -> entity?.categories?.map { it.toFavouriteCategory() }.orEmpty() @@ -121,6 +123,7 @@ class FavouritesRepository(private val db: MangaDatabase) { private fun observeOrder(categoryId: Long): Flow { return db.favouriteCategoriesDao.observe(categoryId) + .filterNotNull() .map { x -> SortOrder(x.order, SortOrder.NEWEST) } .distinctUntilChanged() } 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 4433f978d..81eb9c38c 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 @@ -6,6 +6,7 @@ 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.updateLayoutParams import androidx.core.view.updatePadding import com.google.android.material.snackbar.Snackbar @@ -18,6 +19,7 @@ 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.databinding.ItemEmptyStateBinding import org.koitharu.kotatsu.favourites.ui.categories.CategoriesActivity import org.koitharu.kotatsu.favourites.ui.categories.CategoriesEditDelegate import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel @@ -31,13 +33,15 @@ class FavouritesContainerFragment : BaseFragment(), FavouritesTabLongClickListener, CategoriesEditDelegate.CategoriesEditCallback, - ActionModeListener { + 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 onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -52,9 +56,7 @@ class FavouritesContainerFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val adapter = FavouritesPagerAdapter(this, this) - viewModel.visibleCategories.value?.let { - adapter.replaceData(it) - } + viewModel.visibleCategories.value?.let(::onCategoriesChanged) binding.pager.adapter = adapter pagerAdapter = adapter TabLayoutMediator(binding.tabs, binding.pager, adapter).attach() @@ -66,6 +68,7 @@ class FavouritesContainerFragment : override fun onDestroyView() { pagerAdapter = null + stubBinding = null super.onDestroyView() } @@ -101,6 +104,15 @@ class FavouritesContainerFragment : 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 + } } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { @@ -130,6 +142,12 @@ class FavouritesContainerFragment : return true } + override fun onClick(v: View) { + when (v.id) { + R.id.button_retry -> editDelegate.createCategory() + } + } + override fun onDeleteCategory(category: FavouriteCategory) { viewModel.deleteCategory(category.id) } @@ -193,6 +211,18 @@ class FavouritesContainerFragment : 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() 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 7aac74e62..625b63d33 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 @@ -31,7 +31,7 @@ class FavouritesCategoriesViewModel( repository.observeCategories(), observeAllCategoriesVisible(), ) { list, showAll -> - mapCategories(list, showAll, showAll) + mapCategories(list, showAll, showAll && list.isNotEmpty()) }.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default) fun createCategory(name: String) { diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt index 476fa6fb1..157058560 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/list/FavouritesListViewModel.kt @@ -1,9 +1,13 @@ package org.koitharu.kotatsu.favourites.ui.list +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope +import androidx.recyclerview.widget.RecyclerView.NO_ID 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 @@ -24,6 +28,14 @@ class FavouritesListViewModel( settings: AppSettings, ) : MangaListViewModel(settings), CountersProvider { + var sortOrder: LiveData = 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) { repository.observeAll(SortOrder.NEWEST) diff --git a/app/src/main/res/layout/fragment_favourites.xml b/app/src/main/res/layout/fragment_favourites.xml index 0f7e61994..d93d500b3 100644 --- a/app/src/main/res/layout/fragment_favourites.xml +++ b/app/src/main/res/layout/fragment_favourites.xml @@ -17,4 +17,10 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 41dad2021..5132657f0 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -278,4 +278,5 @@ Главы будут удалены в фоновом режиме. Это может занять какое-то время Скрыть Доступны новые источники манги + Нет категорий избранного \ 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 692597cee..e1f0d34a4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -281,4 +281,5 @@ Chapters will be removed in the background. It can take some time Hide New manga sources are available + No favourite categories \ No newline at end of file