Move more composable logic

pull/1952/head
Alex Baker 3 years ago
parent 3e3de3c1d6
commit 85b8092982

@ -2,18 +2,15 @@ package com.todoroo.astrid.tags
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import androidx.compose.foundation.layout.padding import android.view.View
import androidx.compose.runtime.Composable import android.view.ViewGroup
import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.stringResource import com.google.android.material.composethemeadapter.MdcTheme
import androidx.compose.ui.unit.dp
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R import org.tasks.R
import org.tasks.compose.DisabledText
import org.tasks.compose.collectAsStateLifecycleAware import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.data.TagData import org.tasks.compose.edit.TagsRow
import org.tasks.tags.TagPickerActivity import org.tasks.tags.TagPickerActivity
import org.tasks.ui.ChipGroup
import org.tasks.ui.ChipProvider import org.tasks.ui.ChipProvider
import org.tasks.ui.TaskEditControlComposeFragment import org.tasks.ui.TaskEditControlComposeFragment
import javax.inject.Inject import javax.inject.Inject
@ -28,24 +25,19 @@ class TagsControlSet : TaskEditControlComposeFragment() {
startActivityForResult(intent, REQUEST_TAG_PICKER_ACTIVITY) startActivityForResult(intent, REQUEST_TAG_PICKER_ACTIVITY)
} }
@Composable override fun bind(parent: ViewGroup?): View =
override fun Body() { (parent as ComposeView).apply {
val tags = viewModel.selectedTags.collectAsStateLifecycleAware() setContent {
ChipGroup(modifier = Modifier.padding(top = 20.dp, bottom = 20.dp, end = 16.dp)) { MdcTheme {
if (tags.value.isEmpty()) { TagsRow(
DisabledText(text = stringResource(id = R.string.add_tags)) tags = viewModel.selectedTags.collectAsStateLifecycleAware().value,
} else { colorProvider = { chipProvider.getColor(it) },
tags.value.sortedBy(TagData::name).forEach { tag -> onClick = this@TagsControlSet::onRowClick
chipProvider.TagChip(tag, this@TagsControlSet::onRowClick) )
}
} }
} }
} }
override val isClickable = true
override val icon = R.drawable.ic_outline_label_24px
override fun controlId() = TAG override fun controlId() = TAG
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

@ -0,0 +1,130 @@
package org.tasks.compose
import android.content.res.Configuration
import androidx.annotation.DrawableRes
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.android.material.composethemeadapter.MdcTheme
import org.tasks.themes.CustomIcons
@Composable
fun Chip(
@DrawableRes icon: Int?,
name: String?,
theme: Int,
showText: Boolean,
showIcon: Boolean,
onClick: () -> Unit,
colorProvider: (Int) -> Int,
) {
Chip(
color = Color(colorProvider(theme)),
text = if (showText) name else null,
icon = if (showIcon && icon != null) icon else null,
onClick = onClick,
)
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun Chip(
text: String? = null,
icon: Int? = null,
color: Color,
onClick: () -> Unit = {},
) {
CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false
) {
Chip(
onClick = onClick,
border = BorderStroke(1.dp, color = color),
leadingIcon = {
if (text != null) {
ChipIcon(iconRes = icon)
}
},
modifier = Modifier.defaultMinSize(minHeight = 26.dp),
colors = ChipDefaults.chipColors(
backgroundColor = color.copy(alpha = .1f),
contentColor = MaterialTheme.colors.onSurface
),
) {
if (text == null) {
ChipIcon(iconRes = icon)
}
text?.let {
Text(
text = it,
style = MaterialTheme.typography.caption,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
}
}
}
@Composable
private fun ChipIcon(iconRes: Int?) {
iconRes?.let {
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
modifier = Modifier.size(18.dp)
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TasksChipIconAndTextPreview() {
MdcTheme {
Chip(
text = "Home",
icon = CustomIcons.getIconResId(CustomIcons.LABEL),
color = Color.Red,
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TasksChipIconPreview() {
MdcTheme {
Chip(
text = null,
icon = CustomIcons.getIconResId(CustomIcons.LABEL),
color = Color.Red,
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TasksChipTextPreview() {
MdcTheme {
Chip(
text = "Home",
icon = null,
color = Color.Red,
)
}
}

@ -0,0 +1,17 @@
package org.tasks.compose
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.google.accompanist.flowlayout.FlowRow
@Composable
fun ChipGroup(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
FlowRow(
mainAxisSpacing = 4.dp,
crossAxisSpacing = 4.dp,
modifier = modifier,
) {
content()
}
}

@ -0,0 +1,25 @@
package org.tasks.compose
import androidx.compose.runtime.Composable
import com.todoroo.astrid.api.Filter
import org.tasks.themes.CustomIcons
@Composable
fun FilterChip(
filter: Filter,
defaultIcon: Int,
showText: Boolean,
showIcon: Boolean,
onClick: (Filter) -> Unit,
colorProvider: (Int) -> Int,
) {
Chip(
CustomIcons.getIcon(filter.icon, defaultIcon),
filter.listingTitle,
filter.tint,
showText,
showIcon,
onClick = { onClick(filter) },
colorProvider = colorProvider,
)
}

@ -0,0 +1,37 @@
package org.tasks.compose.edit
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.todoroo.astrid.api.Filter
import org.tasks.R
import org.tasks.compose.ChipGroup
import org.tasks.compose.FilterChip
import org.tasks.compose.TaskEditRow
@Composable
fun ListRow(
list: Filter?,
colorProvider: (Int) -> Int,
onClick: () -> Unit,
) {
TaskEditRow(
iconRes = R.drawable.ic_list_24px,
content = {
ChipGroup(modifier = Modifier.padding(vertical = 20.dp)) {
if (list != null) {
FilterChip(
filter = list,
defaultIcon = R.drawable.ic_list_24px,
showText = true,
showIcon = true,
onClick = { onClick() },
colorProvider = colorProvider
)
}
}
},
onClick = onClick
)
}

@ -0,0 +1,48 @@
package org.tasks.compose.edit
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import org.tasks.R
import org.tasks.compose.Chip
import org.tasks.compose.ChipGroup
import org.tasks.compose.DisabledText
import org.tasks.compose.TaskEditRow
import org.tasks.data.TagData
import org.tasks.themes.CustomIcons
@Composable
fun TagsRow(
tags: List<TagData>,
colorProvider: (Int) -> Int,
onClick: () -> Unit,
) {
TaskEditRow(
iconRes = R.drawable.ic_outline_label_24px,
content = {
ChipGroup(modifier = Modifier.padding(top = 20.dp, bottom = 20.dp, end = 16.dp)) {
if (tags.isEmpty()) {
DisabledText(text = stringResource(id = R.string.add_tags))
} else {
tags.sortedBy(TagData::name).forEach { tag ->
Chip(
icon = CustomIcons.getIcon(
tag.getIcon()!!,
R.drawable.ic_outline_label_24px
),
name = tag.name,
theme = tag.getColor()!!,
showText = true,
showIcon = true,
onClick = onClick,
colorProvider = colorProvider,
)
}
}
}
},
onClick = onClick
)
}

@ -20,6 +20,7 @@ import com.todoroo.astrid.core.SortHelper.SORT_DUE
import com.todoroo.astrid.core.SortHelper.SORT_START import com.todoroo.astrid.core.SortHelper.SORT_START
import com.todoroo.astrid.ui.CheckableImageView import com.todoroo.astrid.ui.CheckableImageView
import org.tasks.R import org.tasks.R
import org.tasks.compose.ChipGroup
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.databinding.TaskAdapterRowBinding import org.tasks.databinding.TaskAdapterRowBinding
import org.tasks.date.DateTimeUtils.newDateTime import org.tasks.date.DateTimeUtils.newDateTime
@ -28,7 +29,6 @@ import org.tasks.markdown.Markdown
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.time.DateTimeUtils.startOfDay import org.tasks.time.DateTimeUtils.startOfDay
import org.tasks.ui.CheckBoxProvider import org.tasks.ui.CheckBoxProvider
import org.tasks.ui.ChipGroup
import org.tasks.ui.ChipProvider import org.tasks.ui.ChipProvider
import java.time.format.FormatStyle import java.time.format.FormatStyle
import java.util.* import java.util.*

@ -1,5 +1,6 @@
package org.tasks.themes package org.tasks.themes
import androidx.annotation.DrawableRes
import org.tasks.R import org.tasks.R
object CustomIcons { object CustomIcons {
@ -218,4 +219,7 @@ object CustomIcons {
@JvmStatic @JvmStatic
fun getIndex(position: Int) = getIconList()[position] fun getIndex(position: Int) = getIconList()[position]
@DrawableRes
fun getIcon(index: Int, def: Int) = getIconResId(index) ?: def
} }

@ -1,23 +1,7 @@
package org.tasks.ui package org.tasks.ui
import android.app.Activity import android.app.Activity
import android.content.res.Configuration
import androidx.annotation.DrawableRes
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.google.accompanist.flowlayout.FlowRow
import com.google.android.material.composethemeadapter.MdcTheme
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
@ -27,16 +11,14 @@ import com.todoroo.astrid.data.Task
import org.tasks.R import org.tasks.R
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.billing.Inventory import org.tasks.billing.Inventory
import org.tasks.data.TagData import org.tasks.compose.Chip
import org.tasks.compose.FilterChip
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.date.DateTimeUtils.toDateTime import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.extensions.formatNumber import org.tasks.extensions.formatNumber
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.themes.CustomIcons
import org.tasks.themes.CustomIcons.getIconResId
import org.tasks.themes.ThemeColor
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.*
@ -79,13 +61,14 @@ class ChipProvider @Inject constructor(
false false
) )
} }
TasksChip( Chip(
R.drawable.ic_pending_actions_24px, R.drawable.ic_pending_actions_24px,
text, text,
0, 0,
showText = true, showText = true,
showIcon = true, showIcon = true,
onClick = {}, onClick = {},
colorProvider = this::getColor,
) )
} }
@ -95,7 +78,7 @@ class ChipProvider @Inject constructor(
compact: Boolean, compact: Boolean,
onClick: () -> Unit, onClick: () -> Unit,
) { ) {
TasksChip( Chip(
if (task.isCollapsed) R.drawable.ic_keyboard_arrow_down_black_24dp else R.drawable.ic_keyboard_arrow_up_black_24dp, if (task.isCollapsed) R.drawable.ic_keyboard_arrow_down_black_24dp else R.drawable.ic_keyboard_arrow_up_black_24dp,
if (compact) locale.formatNumber(task.children) else activity if (compact) locale.formatNumber(task.children) else activity
.resources .resources
@ -104,24 +87,7 @@ class ChipProvider @Inject constructor(
showText = true, showText = true,
showIcon = true, showIcon = true,
onClick = onClick, onClick = onClick,
) colorProvider = this::getColor,
}
@Composable
fun FilterChip(
filter: Filter,
defaultIcon: Int,
showText: Boolean = this@ChipProvider.showText,
showIcon: Boolean = this@ChipProvider.showIcon,
onClick: (Any) -> Unit,
) {
TasksChip(
getIcon(filter.icon, defaultIcon),
filter.listingTitle,
filter.tint,
showText,
showIcon,
onClick = { onClick(filter) },
) )
} }
@ -144,7 +110,10 @@ class ChipProvider @Inject constructor(
FilterChip( FilterChip(
filter = PlaceFilter(location.place), filter = PlaceFilter(location.place),
defaultIcon = R.drawable.ic_outline_place_24px, defaultIcon = R.drawable.ic_outline_place_24px,
onClick = onClick onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
) )
} }
if (!isSubtask && preferences.showListChip) { if (!isSubtask && preferences.showListChip) {
@ -153,7 +122,10 @@ class ChipProvider @Inject constructor(
FilterChip( FilterChip(
filter = list, filter = list,
defaultIcon = R.drawable.ic_list_24px, defaultIcon = R.drawable.ic_list_24px,
onClick = onClick onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
) )
} }
} else if (!isNullOrEmpty(task.caldav) && filter !is CaldavFilter) { } else if (!isNullOrEmpty(task.caldav) && filter !is CaldavFilter) {
@ -161,7 +133,10 @@ class ChipProvider @Inject constructor(
FilterChip( FilterChip(
filter = list, filter = list,
defaultIcon = R.drawable.ic_list_24px, defaultIcon = R.drawable.ic_list_24px,
onClick = onClick onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
) )
} }
} }
@ -178,157 +153,22 @@ class ChipProvider @Inject constructor(
FilterChip( FilterChip(
filter = it, filter = it,
defaultIcon = R.drawable.ic_outline_label_24px, defaultIcon = R.drawable.ic_outline_label_24px,
onClick = onClick
)
}
}
}
@Composable
fun TagChip(tag: TagData, onClick: () -> Unit) {
TasksChip(
getIcon(tag.getIcon()!!, R.drawable.ic_outline_label_24px),
tag.name,
tag.getColor()!!,
showText = true,
showIcon = true,
onClick = onClick, onClick = onClick,
showText = showText,
showIcon = showIcon,
colorProvider = this::getColor,
) )
} }
}
@Composable
fun TasksChip(
@DrawableRes icon: Int?,
name: String?,
theme: Int,
showText: Boolean,
showIcon: Boolean,
onClick: () -> Unit,
) {
val color =
getColor(theme)?.primaryColor ?: activity.getColor(R.color.default_chip_background)
TasksChip(
color = Color(color),
text = if (showText) name else null,
icon = if (showIcon && icon != null) icon else null,
onClick = onClick,
)
} }
@DrawableRes fun getColor(theme: Int): Int {
private fun getIcon(index: Int, def: Int) = getIconResId(index) ?: def
private fun getColor(theme: Int): ThemeColor? {
if (theme != 0) { if (theme != 0) {
val color = colorProvider.getThemeColor(theme, true) val color = colorProvider.getThemeColor(theme, true)
if (color.isFree || inventory.purchasedThemes()) { if (color.isFree || inventory.purchasedThemes()) {
return color return color.primaryColor
}
}
return null
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun TasksChip(
text: String? = null,
icon: Int? = null,
color: Color,
onClick: () -> Unit = {},
) {
CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false
) {
Chip(
onClick = onClick,
border = BorderStroke(1.dp, color = color),
leadingIcon = {
if (text != null) {
ChipIcon(iconRes = icon)
}
},
modifier = Modifier.defaultMinSize(minHeight = 26.dp),
colors = ChipDefaults.chipColors(
backgroundColor = color.copy(alpha = .1f),
contentColor = MaterialTheme.colors.onSurface
),
) {
if (text == null) {
ChipIcon(iconRes = icon)
}
text?.let {
Text(
text = it,
style = MaterialTheme.typography.caption,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
} }
} }
} return activity.getColor(R.color.default_chip_background)
@Composable
fun ChipGroup(modifier: Modifier = Modifier, content: @Composable () -> Unit) {
FlowRow(
mainAxisSpacing = 4.dp,
crossAxisSpacing = 4.dp,
modifier = modifier,
) {
content()
}
}
@Composable
fun ChipIcon(iconRes: Int?) {
iconRes?.let {
Icon(
painter = painterResource(id = iconRes),
contentDescription = null,
modifier = Modifier.size(18.dp)
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TasksChipIconAndTextPreview() {
MdcTheme {
TasksChip(
text = "Home",
icon = getIconResId(CustomIcons.LABEL),
color = Color.Red,
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TasksChipIconPreview() {
MdcTheme {
TasksChip(
text = null,
icon = getIconResId(CustomIcons.LABEL),
color = Color.Red,
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun TasksChipTextPreview() {
MdcTheme {
TasksChip(
text = "Home",
icon = null,
color = Color.Red,
)
} }
} }

@ -2,10 +2,10 @@ package org.tasks.ui
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import androidx.compose.foundation.layout.padding import android.view.View
import androidx.compose.runtime.Composable import android.view.ViewGroup
import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.astrid.api.CaldavFilter import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter import com.todoroo.astrid.api.GtasksFilter
@ -13,39 +13,36 @@ import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R import org.tasks.R
import org.tasks.activities.ListPicker import org.tasks.activities.ListPicker
import org.tasks.compose.collectAsStateLifecycleAware import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.compose.edit.ListRow
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class ListFragment : TaskEditControlComposeFragment() { class ListFragment : TaskEditControlComposeFragment() {
@Inject lateinit var chipProvider: ChipProvider @Inject lateinit var chipProvider: ChipProvider
@Composable override fun bind(parent: ViewGroup?): View =
override fun Body() { (parent as ComposeView).apply {
val list = viewModel.selectedList.collectAsStateLifecycleAware() setContent {
val selectedList = list.value ?: return MdcTheme {
ChipGroup(modifier = Modifier.padding(vertical = 20.dp)) { ListRow(
chipProvider.FilterChip( list = viewModel.selectedList.collectAsStateLifecycleAware().value,
filter = selectedList, colorProvider = { chipProvider.getColor(it) },
defaultIcon = R.drawable.ic_list_24px, onClick = {
showText = true, ListPicker.newListPicker(
showIcon = true, viewModel.selectedList.value!!,
onClick = { openPicker() } this@ListFragment,
REQUEST_CODE_SELECT_LIST
) )
.show(parentFragmentManager, FRAG_TAG_GOOGLE_TASK_LIST_SELECTION)
}
)
}
} }
} }
override val icon = R.drawable.ic_list_24px
override fun controlId() = TAG override fun controlId() = TAG
override fun onRowClick() = openPicker()
override val isClickable = true
private fun openPicker() =
ListPicker.newListPicker(viewModel.selectedList.value!!, this, REQUEST_CODE_SELECT_LIST)
.show(parentFragmentManager, FRAG_TAG_GOOGLE_TASK_LIST_SELECTION)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_SELECT_LIST) { if (requestCode == REQUEST_CODE_SELECT_LIST) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {

Loading…
Cancel
Save