Skip to content

Commit

Permalink
[feat]: sorting crashes
Browse files Browse the repository at this point in the history
  • Loading branch information
F0x1d committed Jul 28, 2024
1 parent a59177d commit 056a598
Show file tree
Hide file tree
Showing 16 changed files with 223 additions and 21 deletions.
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ android {
defaultConfig {
applicationId = logFoxPackageName

versionCode = 60
versionName = "2.0.0"
versionCode = 61
versionName = "2.0.1"
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,8 @@ class FileConverter {
@TypeConverter
fun fromFile(value: File) = value.absolutePath
}

data class AppCrashesCount(
val lastCrash: AppCrash,
val count: Int = 1,
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.f0x1d.logfox.database.entity.CrashType
import com.f0x1d.logfox.model.logline.LogLine
import com.f0x1d.logfox.model.preferences.ShowLogValues
import com.f0x1d.logfox.preferences.shared.base.BasePreferences
import com.f0x1d.logfox.preferences.shared.crashes.CrashesSort
import dagger.hilt.android.qualifiers.ApplicationContext
import java.util.Date
import javax.inject.Inject
Expand Down Expand Up @@ -157,6 +158,20 @@ class AppPreferences @Inject constructor(

val showLogValues get() = cachedShowLogValues ?: updateCachedShowLogsValues()

val crashesSortType get() = flowSharedPreferences.getEnum(
key = "pref_crashes_sort_type",
defaultValue = CrashesSort.NEW,
)
val crashesSortReversedOrder get() = flowSharedPreferences.getBoolean(
key = "pref_crashes_sort_reversed_order",
defaultValue = false,
)

fun updateCrashesSortSettings(sortType: CrashesSort, sortInReversedOrder: Boolean) {
put("pref_crashes_sort_type", sortType.name)
put("pref_crashes_sort_reversed_order", sortInReversedOrder)
}

fun collectingFor(crashType: CrashType) = get(
key = "pref_collect_${crashType.readableName.lowercase()}",
defaultValue = true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.f0x1d.logfox.preferences.shared.crashes

import androidx.annotation.Keep
import androidx.annotation.StringRes
import com.f0x1d.logfox.database.entity.AppCrashesCount
import com.f0x1d.logfox.strings.Strings

@Keep
enum class CrashesSort(
@StringRes val titleRes: Int,
val sorter: (List<AppCrashesCount>) -> List<AppCrashesCount> = { it },
) {
NAME(
titleRes = Strings.sort_by_name,
sorter = { crashes ->
crashes.sortedBy { it.lastCrash.appName ?: it.lastCrash.packageName }
},
),
NEW(
titleRes = Strings.sort_by_new,
sorter = { crashes ->
crashes.sortedByDescending { it.lastCrash.dateAndTime }
},
),
COUNT(
titleRes = Strings.sort_by_count,
sorter = { crashes ->
crashes.sortedByDescending { it.count }
},
),
}
13 changes: 13 additions & 0 deletions core/core-ui/src/main/res/drawable/ic_sort.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportHeight="24"
android:viewportWidth="24"
android:width="24dp">

<path
android:fillColor="@android:color/white"
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z" />

</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import com.f0x1d.logfox.arch.adapter.BaseListAdapter
import com.f0x1d.logfox.database.entity.AppCrashesCount
import com.f0x1d.logfox.feature.crashes.databinding.ItemCrashBinding
import com.f0x1d.logfox.feature.crashes.model.AppCrashesCount
import com.f0x1d.logfox.feature.crashes.ui.viewholder.CrashViewHolder

class CrashesAdapter(
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@ import com.f0x1d.logfox.arch.ui.fragment.BaseViewModelFragment
import com.f0x1d.logfox.context.isHorizontalOrientation
import com.f0x1d.logfox.feature.crashes.R
import com.f0x1d.logfox.feature.crashes.adapter.CrashesAdapter
import com.f0x1d.logfox.feature.crashes.databinding.DialogSortingBinding
import com.f0x1d.logfox.feature.crashes.databinding.FragmentCrashesBinding
import com.f0x1d.logfox.feature.crashes.databinding.ItemSortBinding
import com.f0x1d.logfox.feature.crashes.viewmodel.list.CrashesViewModel
import com.f0x1d.logfox.navigation.Directions
import com.f0x1d.logfox.preferences.shared.crashes.CrashesSort
import com.f0x1d.logfox.strings.Strings
import com.f0x1d.logfox.ui.density.dpToPx
import com.f0x1d.logfox.ui.dialog.showAreYouSureClearDialog
import com.f0x1d.logfox.ui.dialog.showAreYouSureDeleteDialog
import com.f0x1d.logfox.ui.view.setClickListenerOn
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.search.SearchView
import dagger.hilt.android.AndroidEntryPoint
Expand Down Expand Up @@ -95,9 +100,14 @@ class CrashesFragment: BaseViewModelFragment<CrashesViewModel, FragmentCrashesBi
}
}

searchBar.menu.setClickListenerOn(R.id.clear_item) {
showAreYouSureClearDialog {
viewModel.clearCrashes()
searchBar.menu.apply {
setClickListenerOn(R.id.sort_item) {
showSortDialog()
}
setClickListenerOn(R.id.clear_item) {
showAreYouSureClearDialog {
viewModel.clearCrashes()
}
}
}

Expand Down Expand Up @@ -146,4 +156,48 @@ class CrashesFragment: BaseViewModelFragment<CrashesViewModel, FragmentCrashesBi
addCallback(viewLifecycleOwner, closeSearchOnBackPressedCallback)
}
}

private fun showSortDialog() {
var selectedSortType = viewModel.currentSort
var sortInReversedOrder = viewModel.currentSortInReversedOrder

val dialogBinding = DialogSortingBinding.inflate(layoutInflater)
CrashesSort.entries.map { type ->
ItemSortBinding.inflate(layoutInflater).root.apply {
id = View.generateViewId()
text = getString(type.titleRes)
tag = type

setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
selectedSortType = type
}
}
}
}.forEach { button ->
dialogBinding.rgSorting.apply {
addView(button)

if (button.tag == viewModel.currentSort) {
check(button.id)
}
}
}

dialogBinding.reverseSwitch.apply {
isChecked = sortInReversedOrder
setOnCheckedChangeListener { _, isChecked -> sortInReversedOrder = isChecked }
}

MaterialAlertDialogBuilder(requireContext())
.setTitle(Strings.sort)
.setView(dialogBinding.root)
.setPositiveButton(android.R.string.ok) { _, _ ->
viewModel.updateSort(
sortType = selectedSortType,
sortInReversedOrder = sortInReversedOrder,
)
}
.show()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.f0x1d.logfox.feature.crashes.ui.viewholder
import android.annotation.SuppressLint
import com.bumptech.glide.Glide
import com.f0x1d.logfox.arch.ui.viewholder.BaseViewHolder
import com.f0x1d.logfox.database.entity.AppCrashesCount
import com.f0x1d.logfox.feature.crashes.databinding.ItemCrashBinding
import com.f0x1d.logfox.feature.crashes.model.AppCrashesCount
import com.f0x1d.logfox.strings.Strings
import com.f0x1d.logfox.ui.view.loadIcon
import java.util.Date
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import androidx.lifecycle.viewModelScope
import com.f0x1d.logfox.arch.di.DefaultDispatcher
import com.f0x1d.logfox.arch.viewmodel.BaseViewModel
import com.f0x1d.logfox.database.entity.AppCrash
import com.f0x1d.logfox.database.entity.AppCrashesCount
import com.f0x1d.logfox.feature.crashes.core.repository.CrashesRepository
import com.f0x1d.logfox.feature.crashes.di.AppName
import com.f0x1d.logfox.feature.crashes.di.PackageName
import com.f0x1d.logfox.feature.crashes.model.AppCrashesCount
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.SharingStarted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import androidx.lifecycle.viewModelScope
import com.f0x1d.logfox.arch.di.DefaultDispatcher
import com.f0x1d.logfox.arch.viewmodel.BaseViewModel
import com.f0x1d.logfox.database.entity.AppCrash
import com.f0x1d.logfox.database.entity.AppCrashesCount
import com.f0x1d.logfox.feature.crashes.core.repository.CrashesRepository
import com.f0x1d.logfox.feature.crashes.model.AppCrashesCount
import com.f0x1d.logfox.preferences.shared.AppPreferences
import com.f0x1d.logfox.preferences.shared.crashes.CrashesSort
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -23,20 +25,40 @@ import javax.inject.Inject
@HiltViewModel
class CrashesViewModel @Inject constructor(
private val crashesRepository: CrashesRepository,
private val appPreferences: AppPreferences,
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher,
application: Application,
): BaseViewModel(application) {

val crashes = crashesRepository.getAllAsFlow()
val currentSort get() = appPreferences.crashesSortType.get()
val currentSortInReversedOrder get() = appPreferences.crashesSortReversedOrder.get()

val crashes = combine(
crashesRepository.getAllAsFlow(),
appPreferences.crashesSortType.asFlow(),
appPreferences.crashesSortReversedOrder.asFlow(),
) { crashes, sortType, sortInReversedOrder ->
CrashesWithSort(
crashes = crashes,
sortType = sortType,
sortInReversedOrder = sortInReversedOrder,
)
}
.distinctUntilChanged()
.map { crashes ->
val groupedCrashes = crashes.groupBy { it.packageName }
.map { crashesWithSort ->
val groupedCrashes = crashesWithSort.crashes.groupBy { it.packageName }

groupedCrashes.map {
AppCrashesCount(
lastCrash = it.value.first(),
count = it.value.size
)
}.let(crashesWithSort.sortType.sorter).let { result ->
if (crashesWithSort.sortInReversedOrder) {
result.asReversed()
} else {
result
}
}
}
.flowOn(defaultDispatcher)
Expand Down Expand Up @@ -70,6 +92,11 @@ class CrashesViewModel @Inject constructor(

fun updateQuery(query: String) = this.query.update { query }

fun updateSort(sortType: CrashesSort, sortInReversedOrder: Boolean) = appPreferences.updateCrashesSortSettings(
sortType = sortType,
sortInReversedOrder = sortInReversedOrder,
)

fun deleteCrashesByPackageName(appCrash: AppCrash) = launchCatching {
crashesRepository.deleteAllByPackageName(appCrash)
}
Expand All @@ -81,4 +108,10 @@ class CrashesViewModel @Inject constructor(
fun clearCrashes() = launchCatching {
crashesRepository.clear()
}

private data class CrashesWithSort(
val crashes: List<AppCrash>,
val sortType: CrashesSort,
val sortInReversedOrder: Boolean,
)
}
36 changes: 36 additions & 0 deletions feature/feature-crashes/src/main/res/layout/dialog_sorting.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp">

<RadioGroup
android:id="@+id/rg_sorting"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/reverse_switch"/>

<com.google.android.material.checkbox.MaterialCheckBox
android:id="@+id/reverse_switch"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/in_reversed_order"
android:paddingStart="10dp"
android:layout_marginStart="20dp"
android:textColor="?android:textColorSecondary"
app:layout_constraintTop_toBottomOf="@id/rg_sorting"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

</ScrollView>
7 changes: 7 additions & 0 deletions feature/feature-crashes/src/main/res/layout/item_sort.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.radiobutton.MaterialRadioButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:textColor="?android:textColorSecondary" />
8 changes: 7 additions & 1 deletion feature/feature-crashes/src/main/res/menu/crashes_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/sort_item"
android:icon="@drawable/ic_sort"
android:title="@string/sort"
app:showAsAction="ifRoom" />

<item
android:id="@+id/clear_item"
android:icon="@drawable/ic_clear_all"
android:title="@string/clear"
app:showAsAction="ifRoom" />

</menu>
</menu>
5 changes: 5 additions & 0 deletions strings/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,9 @@
<string name="type_crashes">%s сбои</string>
<string name="crashes_of">%s сбои %s</string>
<string name="per_app_notifications_settings">Настройки персонализированных уведомлений для приложений доступны в деталях сбоя и системных настройках LogFox</string>
<string name="sort">Сортировка</string>
<string name="in_reversed_order">В обратном порядке</string>
<string name="sort_by_name">По имени</string>
<string name="sort_by_new">По новизне</string>
<string name="sort_by_count">По количеству сбоев</string>
</resources>
5 changes: 5 additions & 0 deletions strings/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,9 @@
<string name="type_crashes">%s crashes</string>
<string name="crashes_of">%s crashes of %s</string>
<string name="per_app_notifications_settings">Per app notifications settings are available in app\'s crash details and LogFox\'s system settings</string>
<string name="sort">Sort</string>
<string name="in_reversed_order">In reversed order</string>
<string name="sort_by_name">By name</string>
<string name="sort_by_new">By novelty</string>
<string name="sort_by_count">By crashes count</string>
</resources>

0 comments on commit 056a598

Please sign in to comment.