Clearing stats
This commit is contained in:
@@ -32,6 +32,9 @@ interface StatsDao {
|
||||
@Query("SELECT manga_id, SUM(duration) AS d FROM stats GROUP BY manga_id ORDER BY d DESC")
|
||||
suspend fun getDurationStats(): Map<@MapColumn("manga_id") Long, @MapColumn("d") Long>
|
||||
|
||||
@Query("DELETE FROM stats")
|
||||
suspend fun clear()
|
||||
|
||||
@Upsert
|
||||
suspend fun upsert(entity: StatsEntity)
|
||||
}
|
||||
|
||||
@@ -44,4 +44,8 @@ class StatsRepository @Inject constructor(
|
||||
}
|
||||
time
|
||||
}
|
||||
|
||||
suspend fun clearStats() {
|
||||
db.getStatsDao().clear()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
package org.koitharu.kotatsu.stats.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.core.ui.BaseFragment
|
||||
import org.koitharu.kotatsu.core.ui.BaseListAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
|
||||
import org.koitharu.kotatsu.core.util.ext.DIALOG_THEME_CENTERED
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
import org.koitharu.kotatsu.core.util.ext.showOrHide
|
||||
import org.koitharu.kotatsu.databinding.ActivityStatsBinding
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||
@@ -22,7 +31,8 @@ import org.koitharu.kotatsu.stats.domain.StatsRecord
|
||||
import org.koitharu.kotatsu.stats.ui.views.PieChartView
|
||||
|
||||
@AndroidEntryPoint
|
||||
class StatsActivity : BaseActivity<ActivityStatsBinding>(), OnListItemClickListener<Manga> {
|
||||
class StatsActivity : BaseActivity<ActivityStatsBinding>(), OnListItemClickListener<Manga>,
|
||||
PieChartView.OnSegmentClickListener {
|
||||
|
||||
private val viewModel: StatsViewModel by viewModels()
|
||||
|
||||
@@ -33,6 +43,11 @@ class StatsActivity : BaseActivity<ActivityStatsBinding>(), OnListItemClickListe
|
||||
val adapter = BaseListAdapter<StatsRecord>()
|
||||
.addDelegate(ListItemType.FEED, statsAD(this))
|
||||
viewBinding.recyclerView.adapter = adapter
|
||||
viewBinding.chart.onSegmentClickListener = this
|
||||
viewModel.isLoading.observe(this) {
|
||||
viewBinding.progressBar.showOrHide(it)
|
||||
}
|
||||
viewModel.onActionDone.observeEvent(this, ReversibleActionObserver(viewBinding.recyclerView))
|
||||
viewModel.readingStats.observe(this) {
|
||||
val sum = it.sumOf { it.duration }
|
||||
viewBinding.chart.setData(
|
||||
@@ -54,4 +69,37 @@ class StatsActivity : BaseActivity<ActivityStatsBinding>(), OnListItemClickListe
|
||||
override fun onItemClick(item: Manga, view: View) {
|
||||
startActivity(DetailsActivity.newIntent(view.context, item))
|
||||
}
|
||||
|
||||
override fun onSegmentClick(view: PieChartView, segment: PieChartView.Segment) {
|
||||
Toast.makeText(this, segment.label, Toast.LENGTH_SHORT).apply {
|
||||
setGravity(Gravity.TOP, 0, view.top + view.height / 2)
|
||||
}.show()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.opt_stats, menu)
|
||||
return super.onCreateOptionsMenu(menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_clear -> {
|
||||
showClearConfirmDialog()
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showClearConfirmDialog() {
|
||||
MaterialAlertDialogBuilder(this, DIALOG_THEME_CENTERED)
|
||||
.setMessage(R.string.clear_stats_confirm)
|
||||
.setTitle(R.string.clear_stats)
|
||||
.setIcon(R.drawable.ic_delete)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.clear) { _, _ ->
|
||||
viewModel.clear()
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,18 @@ package org.koitharu.kotatsu.stats.ui
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||
import org.koitharu.kotatsu.core.util.ext.call
|
||||
import org.koitharu.kotatsu.stats.data.StatsRepository
|
||||
import org.koitharu.kotatsu.stats.domain.StatsRecord
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -16,7 +22,20 @@ class StatsViewModel @Inject constructor(
|
||||
private val repository: StatsRepository,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val readingStats = flow {
|
||||
emit(repository.getReadingStats())
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, emptyList())
|
||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||
val readingStats = MutableStateFlow<List<StatsRecord>>(emptyList())
|
||||
|
||||
init {
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
readingStats.value = repository.getReadingStats()
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
launchLoadingJob(Dispatchers.Default) {
|
||||
repository.clearStats()
|
||||
readingStats.value = emptyList()
|
||||
onActionDone.call(ReversibleAction(R.string.stats_cleared, null))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,9 @@ class PieChartView @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
override fun onDown(e: MotionEvent): Boolean {
|
||||
if (onSegmentClickListener == null) {
|
||||
return false
|
||||
}
|
||||
val segment = findSegmentIndex(e.x, e.y)
|
||||
if (segment != hightlightedSegment) {
|
||||
hightlightedSegment = segment
|
||||
|
||||
@@ -26,6 +26,21 @@
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:hideAnimationBehavior="outward"
|
||||
app:layout_constraintBottom_toBottomOf="@id/appbar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/appbar"
|
||||
app:showAnimationBehavior="inward"
|
||||
app:trackCornerRadius="0dp"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.koitharu.kotatsu.stats.ui.views.PieChartView
|
||||
android:id="@+id/chart"
|
||||
android:layout_width="0dp"
|
||||
|
||||
12
app/src/main/res/menu/opt_stats.xml
Normal file
12
app/src/main/res/menu/opt_stats.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_clear"
|
||||
android:title="@string/clear_stats"
|
||||
android:titleCondensed="@string/clear"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
@@ -608,4 +608,7 @@
|
||||
<string name="other_manga">Other manga</string>
|
||||
<string name="less_than_minute">Less than a minute</string>
|
||||
<string name="statistics">Statistics</string>
|
||||
<string name="clear_stats">Clear statistics</string>
|
||||
<string name="stats_cleared">Statistics cleared</string>
|
||||
<string name="clear_stats_confirm">Do you really want to clear all reading statistics? This action cannot be undone.</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user