Clear updates feed from options menu
This commit is contained in:
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.tracker.ui
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.*
|
import android.view.*
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
@@ -55,6 +56,9 @@ class FeedFragment : BaseFragment<FragmentFeedBinding>(), PaginationScrollListen
|
|||||||
|
|
||||||
viewModel.content.observe(viewLifecycleOwner, this::onListChanged)
|
viewModel.content.observe(viewLifecycleOwner, this::onListChanged)
|
||||||
viewModel.onError.observe(viewLifecycleOwner, this::onError)
|
viewModel.onError.observe(viewLifecycleOwner, this::onError)
|
||||||
|
viewModel.onFeedCleared.observe(viewLifecycleOwner) {
|
||||||
|
onFeedCleared()
|
||||||
|
}
|
||||||
TrackWorker.getProgressLiveData(view.context.applicationContext)
|
TrackWorker.getProgressLiveData(view.context.applicationContext)
|
||||||
.observe(viewLifecycleOwner, this::onUpdateProgressChanged)
|
.observe(viewLifecycleOwner, this::onUpdateProgressChanged)
|
||||||
}
|
}
|
||||||
@@ -64,17 +68,29 @@ class FeedFragment : BaseFragment<FragmentFeedBinding>(), PaginationScrollListen
|
|||||||
inflater.inflate(R.menu.opt_feed, menu)
|
inflater.inflate(R.menu.opt_feed, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
R.id.action_update -> {
|
return when (item.itemId) {
|
||||||
TrackWorker.startNow(requireContext())
|
R.id.action_update -> {
|
||||||
Snackbar.make(
|
TrackWorker.startNow(requireContext())
|
||||||
binding.recyclerView,
|
Snackbar.make(
|
||||||
R.string.feed_will_update_soon,
|
binding.recyclerView,
|
||||||
Snackbar.LENGTH_SHORT
|
R.string.feed_will_update_soon,
|
||||||
).show()
|
Snackbar.LENGTH_SHORT
|
||||||
true
|
).show()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
R.id.action_clear_feed -> {
|
||||||
|
AlertDialog.Builder(context ?: return false)
|
||||||
|
.setTitle(R.string.clear_updates_feed)
|
||||||
|
.setMessage(R.string.text_clear_updates_feed_prompt)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.clear) { _, _ ->
|
||||||
|
viewModel.clearFeed()
|
||||||
|
}.show()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
else -> super.onOptionsItemSelected(item)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
@@ -95,6 +111,14 @@ class FeedFragment : BaseFragment<FragmentFeedBinding>(), PaginationScrollListen
|
|||||||
feedAdapter?.items = list
|
feedAdapter?.items = list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onFeedCleared() {
|
||||||
|
Snackbar.make(
|
||||||
|
binding.recyclerView,
|
||||||
|
R.string.updates_feed_cleared,
|
||||||
|
Snackbar.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun onError(e: Throwable) {
|
private fun onError(e: Throwable) {
|
||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
binding.recyclerView,
|
binding.recyclerView,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import androidx.lifecycle.MutableLiveData
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancelAndJoin
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
@@ -16,6 +17,7 @@ import org.koitharu.kotatsu.list.ui.model.LoadingFooter
|
|||||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
import org.koitharu.kotatsu.tracker.ui.model.toFeedItem
|
import org.koitharu.kotatsu.tracker.ui.model.toFeedItem
|
||||||
|
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||||
import org.koitharu.kotatsu.utils.ext.mapItems
|
import org.koitharu.kotatsu.utils.ext.mapItems
|
||||||
|
|
||||||
@@ -29,6 +31,7 @@ class FeedViewModel(
|
|||||||
private var loadingJob: Job? = null
|
private var loadingJob: Job? = null
|
||||||
|
|
||||||
val isEmptyState = MutableLiveData(false)
|
val isEmptyState = MutableLiveData(false)
|
||||||
|
val onFeedCleared = SingleLiveEvent<Unit>()
|
||||||
val content = combine(
|
val content = combine(
|
||||||
logList.filterNotNull().mapItems {
|
logList.filterNotNull().mapItems {
|
||||||
it.toFeedItem(context.resources)
|
it.toFeedItem(context.resources)
|
||||||
@@ -40,7 +43,10 @@ class FeedViewModel(
|
|||||||
isHasNextPage -> list + LoadingFooter
|
isHasNextPage -> list + LoadingFooter
|
||||||
else -> list
|
else -> list
|
||||||
}
|
}
|
||||||
}.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, listOf(LoadingState))
|
}.asLiveDataDistinct(
|
||||||
|
viewModelScope.coroutineContext + Dispatchers.Default,
|
||||||
|
listOf(LoadingState)
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadList(append = false)
|
loadList(append = false)
|
||||||
@@ -62,4 +68,15 @@ class FeedViewModel(
|
|||||||
hasNextPage.value = list.isNotEmpty()
|
hasNextPage.value = list.isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clearFeed() {
|
||||||
|
val lastJob = loadingJob
|
||||||
|
loadingJob = launchLoadingJob(Dispatchers.Default) {
|
||||||
|
lastJob?.cancelAndJoin()
|
||||||
|
repository.clearLogs()
|
||||||
|
logList.value = emptyList()
|
||||||
|
isEmptyState.postValue(true)
|
||||||
|
onFeedCleared.postCall(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -68,4 +68,24 @@ inline fun <T, reified R> Array<T>.mapToArray(transform: (T) -> R): Array<R> = A
|
|||||||
transform(get(i))
|
transform(get(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Enum<T>> Array<T>.names() = mapToArray { it.name }
|
fun <T : Enum<T>> Array<T>.names() = mapToArray { it.name }
|
||||||
|
|
||||||
|
fun <T> Collection<T>.isDistinct(): Boolean {
|
||||||
|
val set = HashSet<T>(size)
|
||||||
|
for (item in this) {
|
||||||
|
if (!set.add(item)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set.size == size
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, K> Collection<T>.isDistinctBy(selector: (T) -> K): Boolean {
|
||||||
|
val set = HashSet<K>(size)
|
||||||
|
for (item in this) {
|
||||||
|
if (!set.add(selector(item))) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set.size == size
|
||||||
|
}
|
||||||
@@ -9,4 +9,10 @@
|
|||||||
android:title="@string/update"
|
android:title="@string/update"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_clear_feed"
|
||||||
|
android:orderInCategory="50"
|
||||||
|
android:title="@string/clear_feed"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
@@ -193,4 +193,6 @@
|
|||||||
<string name="clear_cookies">Очистить куки</string>
|
<string name="clear_cookies">Очистить куки</string>
|
||||||
<string name="cookies_cleared">Все куки удалены</string>
|
<string name="cookies_cleared">Все куки удалены</string>
|
||||||
<string name="chapers_checking_progress">Проверка новых глав: %1$d из %2$d</string>
|
<string name="chapers_checking_progress">Проверка новых глав: %1$d из %2$d</string>
|
||||||
|
<string name="clear_feed">Очистить ленту</string>
|
||||||
|
<string name="text_clear_updates_feed_prompt">Вся история обновлений будет очищена и её нельзя будет вернуть. Вы уверены?</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -195,4 +195,6 @@
|
|||||||
<string name="clear_cookies">Clear cookies</string>
|
<string name="clear_cookies">Clear cookies</string>
|
||||||
<string name="cookies_cleared">All cookies was removed</string>
|
<string name="cookies_cleared">All cookies was removed</string>
|
||||||
<string name="chapers_checking_progress">Checking for new chapters: %1$d of %2$d</string>
|
<string name="chapers_checking_progress">Checking for new chapters: %1$d of %2$d</string>
|
||||||
|
<string name="clear_feed">Clear feed</string>
|
||||||
|
<string name="text_clear_updates_feed_prompt">All updates history will be cleared and this action cannot be undone. Are you sure?</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user