Move SectionedDataSource to kmp

pull/2948/head
Alex Baker 1 year ago
parent 59d81f5755
commit 4f2d676ae4

@ -33,7 +33,6 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import org.tasks.filters.GtasksFilter
import org.tasks.compose.CheckBox import org.tasks.compose.CheckBox
import org.tasks.compose.ClearButton import org.tasks.compose.ClearButton
import org.tasks.compose.DisabledText import org.tasks.compose.DisabledText
@ -44,7 +43,9 @@ import org.tasks.data.TaskContainer
import org.tasks.data.entity.Task import org.tasks.data.entity.Task
import org.tasks.data.isHidden import org.tasks.data.isHidden
import org.tasks.filters.Filter import org.tasks.filters.Filter
import org.tasks.filters.GtasksFilter
import org.tasks.tasklist.SectionedDataSource import org.tasks.tasklist.SectionedDataSource
import org.tasks.tasklist.UiItem
import org.tasks.themes.TasksTheme import org.tasks.themes.TasksTheme
import org.tasks.ui.TaskListViewModel import org.tasks.ui.TaskListViewModel
@ -94,7 +95,7 @@ fun SubtaskRow(
if (existingSubtasks is TaskListViewModel.TasksResults.Results) { if (existingSubtasks is TaskListViewModel.TasksResults.Results) {
existingSubtasks existingSubtasks
.tasks .tasks
.filterIsInstance<TaskListViewModel.UiItem.Task>() .filterIsInstance<UiItem.Task>()
.map { it.task } .map { it.task }
.forEach { task -> .forEach { task ->
ExistingSubtaskRow( ExistingSubtaskRow(

@ -1,23 +0,0 @@
package org.tasks.tasklist
import android.content.Context
import androidx.core.content.ContextCompat
import com.todoroo.astrid.core.SortHelper.SORT_START
import org.tasks.R
import org.tasks.date.DateTimeUtils.toDateTime
data class AdapterSection(
var firstPosition: Int,
val value: Long,
var sectionedPosition: Int = 0,
var collapsed: Boolean = false
) {
fun headerColor(context: Context, groupMode: Int, textColor: Int = R.color.text_secondary) =
ContextCompat.getColor(context, if (groupMode == SORT_START
&& value > 0
&& value.toDateTime().plusDays(1).startOfDay().isBeforeNow) {
R.color.overdue
} else {
textColor
})
}

@ -0,0 +1,24 @@
package org.tasks.tasklist
import android.content.Context
import androidx.core.content.ContextCompat
import com.todoroo.astrid.core.SortHelper.SORT_START
import org.tasks.R
import org.tasks.date.DateTimeUtils.toDateTime
fun AdapterSection.headerColor(
context: Context,
groupMode: Int,
textColor: Int = R.color.text_secondary
) =
ContextCompat.getColor(
context,
if (groupMode == SORT_START
&& value > 0
&& value.toDateTime().plusDays(1).startOfDay().isBeforeNow
) {
R.color.overdue
} else {
textColor
}
)

@ -6,9 +6,9 @@ import com.todoroo.astrid.core.SortHelper.SORT_DUE
import com.todoroo.astrid.core.SortHelper.SORT_START import com.todoroo.astrid.core.SortHelper.SORT_START
internal class DiffCallback( internal class DiffCallback(
private val old: SectionedDataSource, private val old: SectionedDataSource,
private val new: SectionedDataSource, private val new: SectionedDataSource,
@Deprecated("") private val adapter: TaskAdapter @Deprecated("") private val adapter: TaskAdapter
) : DiffUtil.Callback() { ) : DiffUtil.Callback() {
private val refreshDates = when (old.groupMode) { private val refreshDates = when (old.groupMode) {

@ -23,7 +23,6 @@ import kotlinx.coroutines.runBlocking
import org.tasks.activities.DragAndDropDiffer import org.tasks.activities.DragAndDropDiffer
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.ui.TaskListViewModel.UiItem
import java.util.LinkedList import java.util.LinkedList
import java.util.Queue import java.util.Queue
import java.util.concurrent.Executors import java.util.concurrent.Executors

@ -6,8 +6,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import org.tasks.filters.EmptyFilter
import org.tasks.filters.SearchFilter
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import com.todoroo.astrid.service.TaskDeleter import com.todoroo.astrid.service.TaskDeleter
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -35,8 +33,10 @@ import org.tasks.data.entity.Task
import org.tasks.data.fetchTasks import org.tasks.data.fetchTasks
import org.tasks.db.QueryUtils import org.tasks.db.QueryUtils
import org.tasks.filters.AstridOrderingFilter import org.tasks.filters.AstridOrderingFilter
import org.tasks.filters.EmptyFilter
import org.tasks.filters.Filter import org.tasks.filters.Filter
import org.tasks.filters.FilterImpl import org.tasks.filters.FilterImpl
import org.tasks.filters.SearchFilter
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.preferences.QueryPreferences import org.tasks.preferences.QueryPreferences
import org.tasks.tasklist.SectionedDataSource import org.tasks.tasklist.SectionedDataSource
@ -56,11 +56,6 @@ class TaskListViewModel @Inject constructor(
private val firebase: Firebase, private val firebase: Firebase,
) : ViewModel() { ) : ViewModel() {
sealed class UiItem {
data class Header(val value: Long): UiItem()
data class Task(val task: TaskContainer): UiItem()
}
sealed interface TasksResults { sealed interface TasksResults {
data object Loading : TasksResults data object Loading : TasksResults
data class Results(val tasks: SectionedDataSource) : TasksResults data class Results(val tasks: SectionedDataSource) : TasksResults

@ -28,6 +28,7 @@ import org.tasks.filters.Filter
import org.tasks.markdown.Markdown import org.tasks.markdown.Markdown
import org.tasks.tasklist.HeaderFormatter import org.tasks.tasklist.HeaderFormatter
import org.tasks.tasklist.SectionedDataSource import org.tasks.tasklist.SectionedDataSource
import org.tasks.tasklist.headerColor
import org.tasks.themes.ColorProvider.Companion.priorityColor import org.tasks.themes.ColorProvider.Companion.priorityColor
import org.tasks.time.DateTimeUtils2.currentTimeMillis import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.startOfDay import org.tasks.time.startOfDay

@ -0,0 +1,8 @@
package org.tasks.tasklist
data class AdapterSection(
var firstPosition: Int,
val value: Long,
var sectionedPosition: Int = 0,
var collapsed: Boolean = false
)

@ -1,12 +1,10 @@
package org.tasks.tasklist package org.tasks.tasklist
import android.util.SparseArray
import androidx.core.util.forEach
import com.todoroo.astrid.core.SortHelper import com.todoroo.astrid.core.SortHelper
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.time.DateTimeUtils2.currentTimeMillis import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.startOfDay import org.tasks.time.startOfDay
import org.tasks.ui.TaskListViewModel.UiItem import java.util.TreeMap
class SectionedDataSource( class SectionedDataSource(
tasks: List<TaskContainer> = emptyList(), tasks: List<TaskContainer> = emptyList(),
@ -19,7 +17,7 @@ class SectionedDataSource(
private val tasks = tasks.toMutableList() private val tasks = tasks.toMutableList()
private val sections = if (disableHeaders || groupMode == SortHelper.GROUP_NONE) { private val sections = if (disableHeaders || groupMode == SortHelper.GROUP_NONE) {
SparseArray() TreeMap<Int, AdapterSection>()
} else { } else {
getSections() getSections()
} }
@ -32,14 +30,13 @@ class SectionedDataSource(
private fun sectionedPositionToPosition(sectionedPosition: Int): Int { private fun sectionedPositionToPosition(sectionedPosition: Int): Int {
if (isHeader(sectionedPosition)) { if (isHeader(sectionedPosition)) {
return sections[sectionedPosition].firstPosition return getSection(sectionedPosition).firstPosition
} }
var offset = 0 var offset = 0
for (i in 0 until sections.size()) { sections.forEach { (_, section) ->
val section = sections.valueAt(i)
if (section.sectionedPosition > sectionedPosition) { if (section.sectionedPosition > sectionedPosition) {
break return@forEach
} }
--offset --offset
} }
@ -50,7 +47,7 @@ class SectionedDataSource(
get() = tasks.size get() = tasks.size
override val size: Int override val size: Int
get() = tasks.size + sections.size() get() = tasks.size + sections.size
override fun get(index: Int) = override fun get(index: Int) =
sections[index] sections[index]
@ -95,13 +92,13 @@ class SectionedDataSource(
TODO("Not yet implemented") TODO("Not yet implemented")
} }
fun getSection(position: Int): AdapterSection = sections[position] fun getSection(position: Int): AdapterSection = sections[position]!!
fun add(position: Int, task: TaskContainer) = tasks.add(sectionedPositionToPosition(position), task) fun add(position: Int, task: TaskContainer) = tasks.add(sectionedPositionToPosition(position), task)
fun removeAt(position: Int): TaskContainer = tasks.removeAt(sectionedPositionToPosition(position)) fun removeAt(position: Int): TaskContainer = tasks.removeAt(sectionedPositionToPosition(position))
private fun getSections(): SparseArray<AdapterSection> { private fun getSections(): TreeMap<Int, AdapterSection> {
val sections = ArrayList<AdapterSection>() val sections = ArrayList<AdapterSection>()
val startOfToday = currentTimeMillis().startOfDay() val startOfToday = currentTimeMillis().startOfDay()
for (i in tasks.indices) { for (i in tasks.indices) {
@ -174,23 +171,22 @@ class SectionedDataSource(
return setSections(sections) return setSections(sections)
} }
private fun setSections(newSections: List<AdapterSection>): SparseArray<AdapterSection> { private fun setSections(newSections: List<AdapterSection>): TreeMap<Int, AdapterSection> {
val sections = SparseArray<AdapterSection>() val sections = TreeMap<Int, AdapterSection>()
newSections.forEachIndexed { index, section -> newSections.forEachIndexed { index, section ->
section.sectionedPosition = section.firstPosition + index section.sectionedPosition = section.firstPosition + index
sections.append(section.sectionedPosition, section) sections[section.sectionedPosition] = section
} }
return sections return sections
} }
fun moveSection(toPosition: Int, offset: Int) { fun moveSection(toPosition: Int, offset: Int) {
val old = sections[toPosition] val old = sections.remove(toPosition)!!
sections.remove(toPosition)
val newSectionedPosition = old.sectionedPosition + offset val newSectionedPosition = old.sectionedPosition + offset
val previousSection = if (isHeader(newSectionedPosition - 1)) sections[newSectionedPosition - 1] else null val previousSection = if (isHeader(newSectionedPosition - 1)) sections[newSectionedPosition - 1] else null
val newFirstPosition = previousSection?.firstPosition ?: (old.firstPosition + offset) val newFirstPosition = previousSection?.firstPosition ?: (old.firstPosition + offset)
val new = AdapterSection(newFirstPosition, old.value, newSectionedPosition, old.collapsed) val new = AdapterSection(newFirstPosition, old.value, newSectionedPosition, old.collapsed)
sections.append(new.sectionedPosition, new) sections[new.sectionedPosition] = new
} }
tailrec fun getNearestHeader(sectionedPosition: Int): Long = tailrec fun getNearestHeader(sectionedPosition: Int): Long =
@ -202,11 +198,7 @@ class SectionedDataSource(
getNearestHeader(sectionedPosition - 1) getNearestHeader(sectionedPosition - 1)
} }
fun getSectionValues(): List<Long> { fun getSectionValues(): List<Long> = sections.map { (_, header) -> header.value }
val values = ArrayList<Long>()
sections.forEach { _, header -> values.add(header.value) }
return values
}
companion object { companion object {
const val HEADER_OVERDUE = -1L const val HEADER_OVERDUE = -1L

@ -0,0 +1,8 @@
package org.tasks.tasklist
import org.tasks.data.TaskContainer
sealed class UiItem {
data class Header(val value: Long): UiItem()
data class Task(val task: TaskContainer): UiItem()
}
Loading…
Cancel
Save