mirror of https://github.com/tasks/tasks
Begin refactoring FilterSettingsActivity
parent
e3edd4797a
commit
be5a4dfc01
@ -0,0 +1,157 @@
|
||||
package org.tasks.activities
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.todoroo.astrid.api.PermaSql
|
||||
import com.todoroo.astrid.core.CriterionInstance
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.tasks.activities.FilterSettingsActivity.Companion.EXTRA_CRITERIA
|
||||
import org.tasks.activities.FilterSettingsActivity.Companion.TOKEN_FILTER
|
||||
import org.tasks.data.dao.TaskDao.TaskCriteria.activeAndVisible
|
||||
import org.tasks.data.db.Database
|
||||
import org.tasks.data.entity.Task
|
||||
import org.tasks.data.rawQuery
|
||||
import org.tasks.data.sql.Field
|
||||
import org.tasks.data.sql.Query
|
||||
import org.tasks.data.sql.UnaryCriterion
|
||||
import org.tasks.db.QueryUtils
|
||||
import org.tasks.filters.CustomFilter
|
||||
import org.tasks.filters.FilterCriteriaProvider
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
|
||||
@HiltViewModel
|
||||
class FilterSettingsViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val filterCriteriaProvider: FilterCriteriaProvider,
|
||||
private val database: Database
|
||||
) : ViewModel() {
|
||||
data class ViewState(
|
||||
val filter: CustomFilter? = null,
|
||||
val fabExtended: Boolean = false,
|
||||
val criteria: ImmutableList<CriterionInstance> = persistentListOf(),
|
||||
)
|
||||
|
||||
private val _viewState = MutableStateFlow(
|
||||
ViewState(
|
||||
filter = savedStateHandle.get<CustomFilter>(TOKEN_FILTER),
|
||||
)
|
||||
)
|
||||
val viewState: StateFlow<ViewState> = _viewState
|
||||
|
||||
init {
|
||||
_viewState.value.filter
|
||||
?.let { filter ->
|
||||
viewModelScope.launch {
|
||||
setCriteria(filterCriteriaProvider.fromString(filter.criterion))
|
||||
}
|
||||
}
|
||||
?: savedStateHandle.get<String>(EXTRA_CRITERIA)?.let { criteria ->
|
||||
viewModelScope.launch {
|
||||
setCriteria(filterCriteriaProvider.fromString(criteria))
|
||||
}
|
||||
}
|
||||
?: setCriteria(emptyList())
|
||||
}
|
||||
|
||||
fun setFabExtended(extended: Boolean) {
|
||||
_viewState.update { it.copy(fabExtended = extended) }
|
||||
}
|
||||
|
||||
private fun setCriteria(criteria: List<CriterionInstance>) {
|
||||
_viewState.update {
|
||||
it.copy(
|
||||
criteria = criteria.ifEmpty { universe() }.toImmutableList(),
|
||||
fabExtended = it.filter == null || criteria.size <= 1,
|
||||
)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
_viewState.update {
|
||||
it.copy(criteria = updateCounts(it.criteria).toImmutableList())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAt(index: Int) {
|
||||
setCriteria(_viewState.value.criteria.toMutableList().apply { removeAt(index) })
|
||||
}
|
||||
|
||||
fun move(from: Int, to: Int) {
|
||||
setCriteria(
|
||||
_viewState.value.criteria
|
||||
.toMutableList()
|
||||
.apply {
|
||||
val criterion = removeAt(from)
|
||||
add(to, criterion)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun addCriteria(instance: CriterionInstance) {
|
||||
setCriteria(_viewState.value.criteria.toMutableList().apply { add(instance) })
|
||||
}
|
||||
|
||||
private suspend fun updateCounts(criteria: List<CriterionInstance>): List<CriterionInstance> {
|
||||
val newList = mutableListOf<CriterionInstance>()
|
||||
var max = 0
|
||||
var last = -1
|
||||
val sql = StringBuilder(Query.select(Field.COUNT).from(Task.TABLE).toString())
|
||||
.append(" WHERE ")
|
||||
|
||||
for (instance in criteria.map { CriterionInstance(it) }) {
|
||||
when (instance.type) {
|
||||
CriterionInstance.TYPE_ADD -> sql.append("OR ")
|
||||
CriterionInstance.TYPE_SUBTRACT -> sql.append("AND NOT ")
|
||||
CriterionInstance.TYPE_INTERSECT -> sql.append("AND ")
|
||||
}
|
||||
|
||||
// special code for all tasks universe
|
||||
if (instance.type == CriterionInstance.TYPE_UNIVERSE || instance.criterion.sql == null) {
|
||||
sql.append(activeAndVisible()).append(' ')
|
||||
} else {
|
||||
var subSql: String = instance.criterion.sql.replace(
|
||||
"?",
|
||||
UnaryCriterion.sanitize(instance.valueFromCriterion!!)
|
||||
)
|
||||
subSql = PermaSql.replacePlaceholdersForQuery(subSql)
|
||||
sql.append(Task.ID).append(" IN (").append(subSql).append(")")
|
||||
}
|
||||
val sqlString = QueryUtils.showHiddenAndCompleted(sql.toString())
|
||||
database.rawQuery(sqlString) { cursor ->
|
||||
cursor.step()
|
||||
instance.start = if (last == -1) cursor.getInt(0) else last
|
||||
instance.end = cursor.getInt(0)
|
||||
last = instance.end
|
||||
max = max(max, last)
|
||||
}
|
||||
newList.add(instance)
|
||||
}
|
||||
for (instance in newList) {
|
||||
instance.max = max
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
private fun universe() = listOf(
|
||||
CriterionInstance().apply {
|
||||
criterion = filterCriteriaProvider.startingUniverse
|
||||
type = CriterionInstance.TYPE_UNIVERSE
|
||||
}
|
||||
)
|
||||
|
||||
fun setCriterion(index: Int, criterionInstance: CriterionInstance) {
|
||||
setCriteria(
|
||||
_viewState.value.criteria.toMutableList().apply {
|
||||
set(index, criterionInstance)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue