diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt index bcb83c411..98086832c 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt @@ -2,8 +2,10 @@ package org.koitharu.kotatsu.explore.ui import android.os.Bundle import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.PopupMenu import androidx.core.graphics.Insets import androidx.core.view.updatePadding import androidx.fragment.app.viewModels @@ -11,11 +13,12 @@ import androidx.recyclerview.widget.RecyclerView import coil.ImageLoader import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.domain.reverseAsync import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner +import org.koitharu.kotatsu.base.ui.util.ReversibleAction import org.koitharu.kotatsu.bookmarks.ui.BookmarksActivity import org.koitharu.kotatsu.databinding.FragmentExploreBinding import org.koitharu.kotatsu.details.ui.DetailsActivity @@ -31,6 +34,7 @@ import org.koitharu.kotatsu.search.ui.MangaListActivity import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.suggestions.ui.SuggestionsActivity import org.koitharu.kotatsu.utils.ext.getDisplayMessage +import javax.inject.Inject @AndroidEntryPoint class ExploreFragment : @@ -67,6 +71,7 @@ class ExploreFragment : } viewModel.onError.observe(viewLifecycleOwner, ::onError) viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga) + viewModel.onActionDone.observe(viewLifecycleOwner, ::onActionDone) } override fun onDestroyView() { @@ -95,6 +100,7 @@ class ExploreFragment : viewModel.openRandom() return } + else -> return } startActivity(intent) @@ -105,6 +111,14 @@ class ExploreFragment : startActivity(intent) } + override fun onItemLongClick(item: ExploreItem.Source, view: View): Boolean { + val menu = PopupMenu(view.context, view) + menu.inflate(R.menu.popup_source) + menu.setOnMenuItemClickListener(SourceMenuListener(item)) + menu.show() + return true + } + override fun onRetryClick(error: Throwable) = Unit override fun onEmptyActionClick() = onManageClick(requireView()) @@ -124,6 +138,37 @@ class ExploreFragment : startActivity(intent) } + private fun onActionDone(action: ReversibleAction) { + val handle = action.handle + val length = if (handle == null) Snackbar.LENGTH_SHORT else Snackbar.LENGTH_LONG + val snackbar = Snackbar.make(binding.recyclerView, action.stringResId, length) + if (handle != null) { + snackbar.setAction(R.string.undo) { handle.reverseAsync() } + } + snackbar.anchorView = (activity as? BottomNavOwner)?.bottomNav + snackbar.show() + } + + private inner class SourceMenuListener( + private val sourceItem: ExploreItem.Source, + ) : PopupMenu.OnMenuItemClickListener { + + override fun onMenuItemClick(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_settings -> { + startActivity(SettingsActivity.newSourceSettingsIntent(requireContext(), sourceItem.source)) + } + + R.id.action_hide -> { + viewModel.hideSource(sourceItem.source) + } + + else -> return false + } + return true + } + } + companion object { fun newInstance() = ExploreFragment() diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt index 6d2657368..7783ebac0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt @@ -4,11 +4,17 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.asFlow import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.domain.ReversibleHandle import org.koitharu.kotatsu.base.ui.BaseViewModel +import org.koitharu.kotatsu.base.ui.util.ReversibleAction import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.explore.domain.ExploreRepository import org.koitharu.kotatsu.explore.ui.model.ExploreItem @@ -16,6 +22,7 @@ import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct +import javax.inject.Inject @HiltViewModel class ExploreViewModel @Inject constructor( @@ -24,6 +31,7 @@ class ExploreViewModel @Inject constructor( ) : BaseViewModel() { val onOpenManga = SingleLiveEvent() + val onActionDone = SingleLiveEvent() val content: LiveData> = isLoading.asFlow().flatMapLatest { loading -> if (loading) { @@ -40,6 +48,16 @@ class ExploreViewModel @Inject constructor( } } + fun hideSource(source: MangaSource) { + launchJob(Dispatchers.Default) { + settings.hiddenSources += source.name + val rollback = ReversibleHandle { + settings.hiddenSources -= source.name + } + onActionDone.postCall(ReversibleAction(R.string.source_disabled, rollback)) + } + } + private fun createContentFlow() = settings.observe() .filter { it == AppSettings.KEY_SOURCES_HIDDEN || diff --git a/app/src/main/res/menu/popup_source.xml b/app/src/main/res/menu/popup_source.xml new file mode 100644 index 000000000..60e497a39 --- /dev/null +++ b/app/src/main/res/menu/popup_source.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5fb25e1e3..10218f426 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -398,4 +398,5 @@ Server side error (%1$d). Please try again later Also clear information about new chapters Compact + Source disabled