Fix some recomposition issues on chips

pull/2260/head
Alex Baker 1 year ago
parent 4018277645
commit e37497b77f

@ -918,9 +918,9 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
showDateTimePicker(task) showDateTimePicker(task)
} }
override fun toggleSubtasks(task: TaskContainer, collapsed: Boolean) { override fun toggleSubtasks(task: Long, collapsed: Boolean) {
lifecycleScope.launch { lifecycleScope.launch {
taskDao.setCollapsed(task.id, collapsed) taskDao.setCollapsed(task, collapsed)
} }
} }

@ -11,6 +11,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Cancel import androidx.compose.material.icons.outlined.Cancel
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
@ -36,7 +37,7 @@ fun Chip(
clear: (() -> Unit)? = null, clear: (() -> Unit)? = null,
) { ) {
Chip( Chip(
color = Color(colorProvider(theme)), color = remember(theme) { Color(colorProvider(theme)) },
text = if (showText) name else null, text = if (showText) name else null,
icon = if (showIcon && icon != null) icon else null, icon = if (showIcon && icon != null) icon else null,
onClick = onClick, onClick = onClick,

@ -1,27 +1,30 @@
package org.tasks.compose package org.tasks.compose
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import org.tasks.R import org.tasks.R
import org.tasks.data.TaskContainer
import java.text.NumberFormat import java.text.NumberFormat
@Composable @Composable
fun SubtaskChip( fun SubtaskChip(
task: TaskContainer, collapsed: Boolean,
children: Int,
compact: Boolean, compact: Boolean,
onClick: () -> Unit, onClick: () -> Unit,
) { ) {
val context = LocalContext.current val context = LocalContext.current
Chip( Chip(
icon = if (task.isCollapsed) icon = if (collapsed)
R.drawable.ic_keyboard_arrow_down_black_24dp R.drawable.ic_keyboard_arrow_down_black_24dp
else else
R.drawable.ic_keyboard_arrow_up_black_24dp, R.drawable.ic_keyboard_arrow_up_black_24dp,
name = if (compact) name = if (compact)
NumberFormat.getInstance().format(task.children) NumberFormat.getInstance().format(children)
else else
context.resources.getQuantityString(R.plurals.subtask_count, task.children, task.children), remember(children) {
context.resources.getQuantityString(R.plurals.subtask_count, children, children)
},
theme = 0, theme = 0,
showText = true, showText = true,
showIcon = true, showIcon = true,

@ -210,7 +210,8 @@ fun ExistingSubtaskRow(
) )
if (task.hasChildren()) { if (task.hasChildren()) {
SubtaskChip( SubtaskChip(
task = task, collapsed = task.isCollapsed,
children = task.children,
compact = true, compact = true,
onClick = onToggleSubtaskClick, onClick = onToggleSubtaskClick,
) )

@ -226,24 +226,26 @@ class TaskViewHolder internal constructor(
) { ) {
chipProvider.Chips( chipProvider.Chips(
filter = filter, filter = filter,
isSubtask = indent > 0, id = task.id,
task = task, children = task.children,
collapsed = task.isCollapsed,
isHidden = task.isHidden,
sortGroup = task.sortGroup,
startDate = task.startDate,
place = task.location?.place,
list = task.caldav,
tagsString = task.tagsString,
isSubtask = task.hasParent(),
isGoogleTask = task.isGoogleTask,
sortByStartDate = sortByStartDate, sortByStartDate = sortByStartDate,
onClick = this::onChipClick toggleSubtasks = { task: Long, collapsed: Boolean -> callback.toggleSubtasks(task, collapsed) },
onClick = { it: Filter -> callback.onClick(it) },
) )
} }
} }
} }
} }
private fun onChipClick(tag: Any) {
if (tag is Filter) {
callback.onClick(tag)
} else if (tag is TaskContainer) {
callback.toggleSubtasks(tag, !tag.isCollapsed)
}
}
private fun onCompleteBoxClick() { private fun onCompleteBoxClick() {
val newState = completeBox.isChecked val newState = completeBox.isChecked
if (newState != task.isCompleted) { if (newState != task.isCompleted) {
@ -263,7 +265,7 @@ class TaskViewHolder internal constructor(
fun onLinkClicked(vh: TaskViewHolder, url: String): Boolean fun onLinkClicked(vh: TaskViewHolder, url: String): Boolean
fun onClick(taskViewHolder: TaskViewHolder) fun onClick(taskViewHolder: TaskViewHolder)
fun onClick(filter: Filter) fun onClick(filter: Filter)
fun toggleSubtasks(task: TaskContainer, collapsed: Boolean) fun toggleSubtasks(task: Long, collapsed: Boolean)
fun onLongPress(taskViewHolder: TaskViewHolder): Boolean fun onLongPress(taskViewHolder: TaskViewHolder): Boolean
fun onChangeDueDate(task: TaskContainer) fun onChangeDueDate(task: TaskContainer)
} }

@ -2,6 +2,9 @@ package org.tasks.ui
import android.app.Activity import android.app.Activity
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.api.CaldavFilter import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
@ -9,19 +12,18 @@ import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.api.TagFilter import com.todoroo.astrid.api.TagFilter
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.R import org.tasks.R
import org.tasks.Strings.isNullOrEmpty
import org.tasks.billing.Inventory import org.tasks.billing.Inventory
import org.tasks.compose.Chip import org.tasks.compose.Chip
import org.tasks.compose.FilterChip import org.tasks.compose.FilterChip
import org.tasks.compose.SubtaskChip import org.tasks.compose.SubtaskChip
import org.tasks.data.TaskContainer import org.tasks.data.Place
import org.tasks.date.DateTimeUtils.toDateTime import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.filters.PlaceFilter import org.tasks.filters.PlaceFilter
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.themes.ColorProvider import org.tasks.themes.ColorProvider
import org.tasks.time.DateTimeUtils.startOfDay import org.tasks.time.DateTimeUtils.startOfDay
import java.time.format.FormatStyle import java.time.format.FormatStyle
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
class ChipProvider @Inject constructor( class ChipProvider @Inject constructor(
@ -42,67 +44,95 @@ class ChipProvider @Inject constructor(
} }
@Composable @Composable
private fun StartDateChip(task: TaskContainer, compact: Boolean, timeOnly: Boolean) { private fun StartDateChip(
val text = if (timeOnly sortGroup: Long?,
&& task.sortGroup?.startOfDay() == task.startDate.startOfDay() startDate: Long,
&& preferences.showGroupHeaders() compact: Boolean,
) { timeOnly: Boolean
task.startDate ) {
.takeIf { Task.hasDueTime(it) } val text by remember(sortGroup, startDate, timeOnly, compact) {
?.let { DateUtilities.getTimeString(activity, it.toDateTime()) } derivedStateOf {
?: return if (
} else { timeOnly &&
DateUtilities.getRelativeDateTime( sortGroup?.startOfDay() == startDate.startOfDay() &&
activity, preferences.showGroupHeaders()
task.startDate, ) {
locale, startDate
if (compact) FormatStyle.SHORT else FormatStyle.MEDIUM, .takeIf { Task.hasDueTime(it) }
false, ?.let { DateUtilities.getTimeString(activity, it.toDateTime()) }
false } else {
DateUtilities.getRelativeDateTime(
activity,
startDate,
locale,
if (compact) FormatStyle.SHORT else FormatStyle.MEDIUM,
false,
false
)
}
}
}
if (text != null) {
Chip(
R.drawable.ic_pending_actions_24px,
text,
0,
showText = true,
showIcon = true,
onClick = {},
colorProvider = this::getColor,
) )
} }
Chip(
R.drawable.ic_pending_actions_24px,
text,
0,
showText = true,
showIcon = true,
onClick = {},
colorProvider = this::getColor,
)
} }
@Composable @Composable
fun Chips( fun Chips(
filter: Filter?, filter: Filter?,
isSubtask: Boolean, id: Long,
task: TaskContainer, children: Int,
collapsed: Boolean,
isHidden: Boolean,
sortGroup: Long?,
startDate: Long,
place: Place?,
tagsString: String?,
sortByStartDate: Boolean, sortByStartDate: Boolean,
onClick: (Any) -> Unit, list: String?,
isSubtask: Boolean,
isGoogleTask: Boolean,
toggleSubtasks: (Long, Boolean) -> Unit,
onClick: (Filter) -> Unit,
) { ) {
if (task.hasChildren() && preferences.showSubtaskChip) { if (children > 0 && remember { preferences.showSubtaskChip }) {
SubtaskChip(task, !showText, onClick = { onClick(task) }) SubtaskChip(
collapsed = collapsed,
children = children,
compact = !showText,
onClick = { toggleSubtasks(id, !collapsed) }
)
} }
if (task.isHidden && preferences.showStartDateChip) { if (isHidden && remember { preferences.showStartDateChip }) {
StartDateChip(task, !showText, sortByStartDate) StartDateChip(sortGroup, startDate, !showText, sortByStartDate)
} }
if (task.hasLocation() && filter !is PlaceFilter && preferences.showPlaceChip) { if (place != null && filter !is PlaceFilter && remember { preferences.showPlaceChip }) {
val location = task.getLocation() FilterChip(
if (location != null) { filter = PlaceFilter(place),
FilterChip( defaultIcon = R.drawable.ic_outline_place_24px,
filter = PlaceFilter(location.place), onClick = onClick,
defaultIcon = R.drawable.ic_outline_place_24px, showText = showText,
onClick = onClick, showIcon = showIcon,
showText = showText, colorProvider = this::getColor,
showIcon = showIcon, )
colorProvider = this::getColor,
)
}
} }
if (!isSubtask && preferences.showListChip && filter !is CaldavFilter) { if (!isSubtask && preferences.showListChip && filter !is CaldavFilter) {
lists.getCaldavList(task.caldav)?.let { list -> remember(list, isGoogleTask) {
lists
.getCaldavList(list)
?.let { if (isGoogleTask) GtasksFilter(it) else CaldavFilter(it) }
}?.let {
FilterChip( FilterChip(
filter = if (task.isGoogleTask) GtasksFilter(list) else CaldavFilter(list), filter = it,
defaultIcon = R.drawable.ic_list_24px, defaultIcon = R.drawable.ic_list_24px,
onClick = onClick, onClick = onClick,
showText = showText, showText = showText,
@ -111,14 +141,15 @@ class ChipProvider @Inject constructor(
) )
} }
} }
val tagString = task.tagsString if (!tagsString.isNullOrBlank() && remember { preferences.showTagChip }) {
if (!isNullOrEmpty(tagString) && preferences.showTagChip) { remember(tagsString, filter) {
val tags = tagString.split(",").toHashSet() val tags = tagsString.split(",").toHashSet()
if (filter is TagFilter) { if (filter is TagFilter) {
tags.remove(filter.uuid) tags.remove(filter.uuid)
}
tags.mapNotNull(lists::getTag)
.sortedBy(TagFilter::listingTitle)
} }
tags.mapNotNull(lists::getTag)
.sortedBy(TagFilter::listingTitle)
.forEach { .forEach {
FilterChip( FilterChip(
filter = it, filter = it,

Loading…
Cancel
Save