Embed task edit row fragments in compose

pull/1952/head
Alex Baker 2 years ago
parent 22de530590
commit d0fcca1a1f

@ -232,6 +232,7 @@ dependencies {
implementation("androidx.activity:activity-compose:1.4.0")
implementation("androidx.compose.material:material-icons-extended:${Versions.compose}")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1")
implementation("androidx.compose.ui:ui-viewbinding:${Versions.compose}")
releaseCompileOnly("androidx.compose.ui:ui-tooling:${Versions.compose}")
implementation("com.google.accompanist:accompanist-flowlayout:${Versions.accompanist}")

@ -21,11 +21,17 @@ import android.view.inputmethod.InputMethodManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.Toolbar
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Divider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidViewBinding
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
@ -36,11 +42,19 @@ import com.google.android.material.appbar.AppBarLayout.Behavior.DragCallback
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task
import com.todoroo.astrid.files.FilesControlSet
import com.todoroo.astrid.notes.CommentsController
import com.todoroo.astrid.repeats.RepeatControlSet
import com.todoroo.astrid.tags.TagsControlSet
import com.todoroo.astrid.timers.TimerControlSet
import com.todoroo.astrid.timers.TimerPlugin
import com.todoroo.astrid.ui.ReminderControlSet
import com.todoroo.astrid.ui.StartDateControlSet
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.launchIn
@ -50,23 +64,32 @@ import kotlinx.coroutines.withContext
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.Strings.isNullOrEmpty
import org.tasks.activities.ListPicker
import org.tasks.analytics.Firebase
import org.tasks.calendars.CalendarPicker
import org.tasks.compose.BeastModeBanner
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.compose.edit.*
import org.tasks.data.*
import org.tasks.databinding.FragmentTaskEditBinding
import org.tasks.databinding.*
import org.tasks.date.DateTimeUtils.newDateTime
import org.tasks.dialogs.DateTimePicker
import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.Linkify
import org.tasks.files.FileHelper
import org.tasks.fragments.CommentBarFragment
import org.tasks.fragments.TaskEditControlSetFragmentManager
import org.tasks.fragments.TaskEditControlSetFragmentManager.Companion.TAG_CREATION
import org.tasks.fragments.TaskEditControlSetFragmentManager.Companion.TAG_DESCRIPTION
import org.tasks.fragments.TaskEditControlSetFragmentManager.Companion.TAG_DUE_DATE
import org.tasks.fragments.TaskEditControlSetFragmentManager.Companion.TAG_LIST
import org.tasks.fragments.TaskEditControlSetFragmentManager.Companion.TAG_PRIORITY
import org.tasks.markdown.MarkdownProvider
import org.tasks.notifications.NotificationManager
import org.tasks.preferences.Preferences
import org.tasks.ui.TaskEditEvent
import org.tasks.ui.TaskEditEventBus
import org.tasks.ui.TaskEditViewModel
import org.tasks.ui.TaskListViewModel
import org.tasks.ui.*
import org.tasks.ui.TaskEditViewModel.Companion.stripCarriageReturns
import java.time.format.FormatStyle
import java.util.*
import javax.inject.Inject
import kotlin.math.abs
@ -86,6 +109,8 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
@Inject lateinit var markdownProvider: MarkdownProvider
@Inject lateinit var taskEditEventBus: TaskEditEventBus
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var locale: Locale
@Inject lateinit var chipProvider: ChipProvider
val editViewModel: TaskEditViewModel by viewModels()
val subtaskViewModel: TaskListViewModel by viewModels()
@ -184,32 +209,35 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
commentsController.initialize(model, binding.comments)
commentsController.reloadView()
val fragmentManager = childFragmentManager
val taskEditControlFragments =
taskEditControlSetFragmentManager.getOrCreateFragments(fragmentManager)
val visibleSize = taskEditControlSetFragmentManager.visibleSize
val fragmentTransaction = fragmentManager.beginTransaction()
for (i in taskEditControlFragments.indices) {
val taskEditControlFragment = taskEditControlFragments[i]
val tag = getString(taskEditControlFragment.controlId())
fragmentTransaction.replace(
TaskEditControlSetFragmentManager.TASK_EDIT_CONTROL_FRAGMENT_ROWS[i],
taskEditControlFragment,
tag)
if (i >= visibleSize) {
fragmentTransaction.hide(taskEditControlFragment)
binding.composeView.setContent {
MdcTheme {
Column {
taskEditControlSetFragmentManager.displayOrder.forEachIndexed { index, tag ->
if (index < taskEditControlSetFragmentManager.visibleSize) {
// TODO: remove ui-viewbinding library when these are all migrated
when (taskEditControlSetFragmentManager.controlSetFragments[tag]) {
TAG_DUE_DATE -> DueDateRow()
TAG_PRIORITY -> PriorityRow()
TAG_DESCRIPTION -> DescriptionRow()
TAG_LIST -> ListRow()
TAG_CREATION -> CreationRow()
CalendarControlSet.TAG -> AndroidViewBinding(TaskEditCalendarBinding::inflate)
StartDateControlSet.TAG -> AndroidViewBinding(TaskEditStartDateBinding::inflate)
ReminderControlSet.TAG -> AndroidViewBinding(TaskEditRemindersBinding::inflate)
LocationControlSet.TAG -> AndroidViewBinding(TaskEditLocationBinding::inflate)
FilesControlSet.TAG -> AndroidViewBinding(TaskEditFilesBinding::inflate)
TimerControlSet.TAG -> AndroidViewBinding(TaskEditTimerBinding::inflate)
TagsControlSet.TAG -> AndroidViewBinding(TaskEditTagsBinding::inflate)
RepeatControlSet.TAG -> AndroidViewBinding(TaskEditRepeatBinding::inflate)
SubtaskControlSet.TAG -> AndroidViewBinding(TaskEditSubtasksBinding::inflate)
else -> throw IllegalArgumentException("Unknown row: $tag")
}
Divider(modifier = Modifier.fillMaxWidth())
}
}
}
}
}
fragmentTransaction.replace(
R.id.comment_bar,
fragmentManager.findFragmentByTag(FRAG_TAG_COMMENT_BAR) ?: CommentBarFragment(),
FRAG_TAG_COMMENT_BAR
)
fragmentTransaction.commit()
for (i in visibleSize - 1 downTo 1) {
binding.controlSets.addView(inflater.inflate(R.layout.task_edit_row_divider, binding.controlSets, false), i)
}
return view
}
@ -228,15 +256,6 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
}
private val beastMode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val transaction = childFragmentManager.beginTransaction()
taskEditControlSetFragmentManager.getOrCreateFragments(childFragmentManager).forEach {
transaction.remove(it)
}
transaction.commit()
activity?.recreate()
}
@OptIn(ExperimentalAnimationApi::class)
private fun showBeastModeHint() {
binding.banner.setContent {
@ -248,7 +267,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
showSettings = {
visible = false
preferences.shownBeastModeHint = true
beastMode.launch(Intent(context, BeastModePreferences::class.java))
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
activity?.recreate()
}.launch(Intent(context, BeastModePreferences::class.java))
firebase.logEvent(R.string.event_banner_beast, R.string.param_click to true)
},
dismiss = {
@ -318,11 +339,6 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
suspend fun save(remove: Boolean = true) = editViewModel.save(remove)
/*
* ======================================================================
* ======================================================= event handlers
* ======================================================================
*/
fun discardButtonClick() {
if (editViewModel.hasChanges()) {
dialogBuilder
@ -351,12 +367,6 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
editViewModel.delete()
}
/*
* ======================================================================
* ========================================== UI component helper classes
* ======================================================================
*/
fun addComment(message: String?, picture: Uri?) {
val model = editViewModel.task
val userActivity = UserActivity()
@ -375,21 +385,144 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_DATE -> {
if (resultCode == Activity.RESULT_OK) {
editViewModel.setDueDate(data!!.getLongExtra(DateTimePicker.EXTRA_TIMESTAMP, 0L))
}
}
REQUEST_CODE_SELECT_LIST -> {
if (resultCode == Activity.RESULT_OK) {
data?.getParcelableExtra<Filter>(ListPicker.EXTRA_SELECTED_FILTER)?.let {
if (it is GtasksFilter || it is CaldavFilter) {
editViewModel.selectedList.value = it
} else {
throw RuntimeException("Unhandled filter type")
}
}
}
}
REQUEST_CODE_PICK_CALENDAR -> {
if (resultCode == Activity.RESULT_OK) {
editViewModel.selectedCalendar.value =
data!!.getStringExtra(CalendarPicker.EXTRA_CALENDAR_ID)
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
private inner class RefreshReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
subtaskViewModel.invalidate()
}
}
@Composable
private fun DueDateRow() {
val dueDate = editViewModel.dueDate.collectAsStateLifecycleAware().value
DueDateRow(
dueDate = if (dueDate == 0L) {
null
} else {
DateUtilities.getRelativeDateTime(
LocalContext.current,
dueDate,
locale,
FormatStyle.FULL,
preferences.alwaysDisplayFullDate,
false
)
},
overdue = dueDate.isOverdue,
onClick = {
DateTimePicker
.newDateTimePicker(
this@TaskEditFragment,
REQUEST_DATE,
editViewModel.dueDate.value,
preferences.getBoolean(
R.string.p_auto_dismiss_datetime_edit_screen,
false
)
)
.show(parentFragmentManager, FRAG_TAG_DATE_PICKER)
}
)
}
@Composable
private fun PriorityRow() {
PriorityRow(
priority = editViewModel.priority.collectAsStateLifecycleAware().value,
onChangePriority = { editViewModel.priority.value = it },
desaturate = preferences.desaturateDarkMode,
)
}
@Composable
private fun DescriptionRow() {
DescriptionRow(
text = editViewModel.description.stripCarriageReturns(),
onChanged = { text -> editViewModel.description = text.toString().trim { it <= ' ' } },
linkify = if (preferences.linkify) linkify else null,
markdownProvider = markdownProvider,
)
}
@Composable
private fun ListRow() {
ListRow(
list = editViewModel.selectedList.collectAsStateLifecycleAware().value,
colorProvider = { chipProvider.getColor(it) },
onClick = {
ListPicker
.newListPicker(
editViewModel.selectedList.value,
this@TaskEditFragment,
REQUEST_CODE_SELECT_LIST
)
.show(
parentFragmentManager,
FRAG_TAG_GOOGLE_TASK_LIST_SELECTION
)
}
)
}
@Composable
fun CreationRow() {
InfoRow(
creationDate = editViewModel.creationDate,
modificationDate = editViewModel.modificationDate,
completionDate = editViewModel.completionDate,
locale = locale,
)
}
companion object {
const val TAG_TASKEDIT_FRAGMENT = "taskedit_fragment"
private const val FRAG_TAG_COMMENT_BAR = "comment_bar"
const val EXTRA_TASK = "extra_task"
const val EXTRA_LIST = "extra_list"
const val EXTRA_LOCATION = "extra_location"
const val EXTRA_TAGS = "extra_tags"
const val EXTRA_ALARMS = "extra_alarms"
private const val FRAG_TAG_GOOGLE_TASK_LIST_SELECTION = "frag_tag_google_task_list_selection"
const val FRAG_TAG_CALENDAR_PICKER = "frag_tag_calendar_picker"
private const val FRAG_TAG_DATE_PICKER = "frag_tag_date_picker"
private const val REQUEST_CODE_SELECT_LIST = 10101
const val REQUEST_CODE_PICK_CALENDAR = 70
private const val REQUEST_DATE = 504
val Long.isOverdue: Boolean
get() = if (Task.hasDueTime(this)) {
newDateTime(this).isBeforeNow
} else {
newDateTime(this).endOfDay().isBeforeNow
}
fun newTaskEditFragment(
task: Task,
list: Filter,

@ -1,7 +1,6 @@
package org.tasks.fragments
import android.content.Context
import androidx.fragment.app.FragmentManager
import com.todoroo.astrid.activity.BeastModePreferences
import com.todoroo.astrid.files.FilesControlSet
import com.todoroo.astrid.repeats.RepeatControlSet
@ -10,52 +9,21 @@ import com.todoroo.astrid.timers.TimerControlSet
import com.todoroo.astrid.ui.ReminderControlSet
import com.todoroo.astrid.ui.StartDateControlSet
import dagger.hilt.android.qualifiers.ActivityContext
import org.tasks.BuildConfig
import org.tasks.R
import org.tasks.preferences.Preferences
import org.tasks.ui.*
import org.tasks.ui.CalendarControlSet
import org.tasks.ui.LocationControlSet
import org.tasks.ui.SubtaskControlSet
import javax.inject.Inject
class TaskEditControlSetFragmentManager @Inject constructor(
@ActivityContext context: Context,
preferences: Preferences?) {
private val controlSetFragments: MutableMap<String, Int> = LinkedHashMap()
private val displayOrder: List<String>
@ActivityContext context: Context,
preferences: Preferences?
) {
val controlSetFragments: MutableMap<String, Int> = LinkedHashMap()
val displayOrder: List<String>
var visibleSize = 0
fun getOrCreateFragments(fragmentManager: FragmentManager): List<TaskEditControlFragment> {
val fragments: MutableList<TaskEditControlFragment> = ArrayList()
for (i in displayOrder.indices) {
val tag = displayOrder[i]
var fragment = fragmentManager.findFragmentByTag(tag) as TaskEditControlFragment?
if (fragment == null) {
val resId = controlSetFragments[tag]
fragment = createFragment(resId!!)
}
fragments.add(fragment)
}
return fragments
}
private fun createFragment(fragmentId: Int): TaskEditControlFragment = when (fragmentId) {
DeadlineControlSet.TAG -> DeadlineControlSet()
PriorityControlSet.TAG -> PriorityControlSet()
DescriptionControlSet.TAG -> DescriptionControlSet()
CalendarControlSet.TAG -> CalendarControlSet()
StartDateControlSet.TAG -> StartDateControlSet()
ReminderControlSet.TAG -> ReminderControlSet()
LocationControlSet.TAG -> LocationControlSet()
FilesControlSet.TAG -> FilesControlSet()
TimerControlSet.TAG -> TimerControlSet()
TagsControlSet.TAG -> TagsControlSet()
RepeatControlSet.TAG -> RepeatControlSet()
ListFragment.TAG -> ListFragment()
SubtaskControlSet.TAG -> SubtaskControlSet()
CreationDateControlSet.TAG -> CreationDateControlSet()
else -> throw RuntimeException("Unsupported fragment")
}
init {
displayOrder = BeastModePreferences.constructOrderedControlList(preferences, context)
val hideAlwaysTrigger = context.getString(R.string.TEA_ctrl_hide_section_pref)
@ -73,44 +41,27 @@ class TaskEditControlSetFragmentManager @Inject constructor(
}
companion object {
val TASK_EDIT_CONTROL_FRAGMENT_ROWS = intArrayOf(
R.id.row_1,
R.id.row_2,
R.id.row_3,
R.id.row_4,
R.id.row_5,
R.id.row_6,
R.id.row_7,
R.id.row_8,
R.id.row_9,
R.id.row_10,
R.id.row_11,
R.id.row_12,
R.id.row_13,
R.id.row_14
)
const val TAG_DESCRIPTION = R.string.TEA_ctrl_notes_pref
const val TAG_CREATION = R.string.TEA_ctrl_creation_date
const val TAG_LIST = R.string.TEA_ctrl_google_task_list
const val TAG_PRIORITY = R.string.TEA_ctrl_importance_pref
const val TAG_DUE_DATE = R.string.TEA_ctrl_when_pref
private val TASK_EDIT_CONTROL_SET_FRAGMENTS = intArrayOf(
DeadlineControlSet.TAG,
TimerControlSet.TAG,
DescriptionControlSet.TAG,
CalendarControlSet.TAG,
PriorityControlSet.TAG,
StartDateControlSet.TAG,
ReminderControlSet.TAG,
LocationControlSet.TAG,
FilesControlSet.TAG,
TagsControlSet.TAG,
RepeatControlSet.TAG,
CreationDateControlSet.TAG,
ListFragment.TAG,
SubtaskControlSet.TAG
TAG_DUE_DATE,
TimerControlSet.TAG,
TAG_DESCRIPTION,
CalendarControlSet.TAG,
TAG_PRIORITY,
StartDateControlSet.TAG,
ReminderControlSet.TAG,
LocationControlSet.TAG,
FilesControlSet.TAG,
TagsControlSet.TAG,
RepeatControlSet.TAG,
TAG_CREATION,
TAG_LIST,
SubtaskControlSet.TAG
)
init {
if (BuildConfig.DEBUG
&& TASK_EDIT_CONTROL_FRAGMENT_ROWS.size != TASK_EDIT_CONTROL_SET_FRAGMENTS.size) {
throw AssertionError()
}
}
}
}

@ -9,6 +9,7 @@ import android.view.ViewGroup
import android.widget.Toast.LENGTH_SHORT
import androidx.compose.ui.platform.ComposeView
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.astrid.activity.TaskEditFragment
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.Strings.isNullOrEmpty
@ -52,8 +53,16 @@ class CalendarControlSet : TaskEditControlFragment() {
},
onClick = {
if (viewModel.eventUri.value.isNullOrBlank()) {
CalendarPicker.newCalendarPicker(this@CalendarControlSet, REQUEST_CODE_PICK_CALENDAR, calendarName)
.show(parentFragmentManager, FRAG_TAG_CALENDAR_PICKER)
CalendarPicker
.newCalendarPicker(
requireParentFragment(),
TaskEditFragment.REQUEST_CODE_PICK_CALENDAR,
calendarName
)
.show(
requireParentFragment().parentFragmentManager,
TaskEditFragment.FRAG_TAG_CALENDAR_PICKER
)
} else {
openCalendarEvent()
}
@ -95,16 +104,6 @@ class CalendarControlSet : TaskEditControlFragment() {
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_PICK_CALENDAR) {
if (resultCode == Activity.RESULT_OK) {
viewModel.selectedCalendar.value = data!!.getStringExtra(CalendarPicker.EXTRA_CALENDAR_ID)
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
private val calendarName: String?
get() = viewModel.selectedCalendar.value?.let { calendarProvider.getCalendar(it)?.name }
@ -129,7 +128,5 @@ class CalendarControlSet : TaskEditControlFragment() {
companion object {
const val TAG = R.string.TEA_ctrl_gcal
private const val FRAG_TAG_CALENDAR_PICKER = "frag_tag_calendar_picker"
private const val REQUEST_CODE_PICK_CALENDAR = 70
}
}

@ -1,36 +0,0 @@
package org.tasks.ui
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import com.google.android.material.composethemeadapter.MdcTheme
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.compose.edit.InfoRow
import java.util.*
import javax.inject.Inject
@AndroidEntryPoint
class CreationDateControlSet : TaskEditControlFragment() {
@Inject lateinit var locale: Locale
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
MdcTheme {
InfoRow(
creationDate = viewModel.creationDate,
modificationDate = viewModel.modificationDate,
completionDate = viewModel.completionDate,
locale = locale,
)
}
}
}
override fun controlId() = TAG
companion object {
const val TAG = R.string.TEA_ctrl_creation_date
}
}

@ -1,86 +0,0 @@
package org.tasks.ui
import android.app.Activity
import android.content.Intent
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.data.Task.Companion.hasDueTime
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.compose.edit.DueDateRow
import org.tasks.date.DateTimeUtils
import org.tasks.dialogs.DateTimePicker
import org.tasks.preferences.Preferences
import java.time.format.FormatStyle
import java.util.*
import javax.inject.Inject
@AndroidEntryPoint
class DeadlineControlSet : TaskEditControlFragment() {
@Inject lateinit var locale: Locale
@Inject lateinit var preferences: Preferences
override fun bind(parent: ViewGroup?) =
(parent as ComposeView).apply {
setContent {
MdcTheme {
val dueDate = viewModel.dueDate.collectAsStateLifecycleAware().value
DueDateRow(
dueDate = if (dueDate == 0L) {
null
} else {
DateUtilities.getRelativeDateTime(
LocalContext.current,
dueDate,
locale,
FormatStyle.FULL,
preferences.alwaysDisplayFullDate,
false
)
},
overdue = dueDate.isOverdue,
onClick = {
val fragmentManager = parentFragmentManager
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
DateTimePicker.newDateTimePicker(
this@DeadlineControlSet,
REQUEST_DATE,
viewModel.dueDate.value,
preferences.getBoolean(R.string.p_auto_dismiss_datetime_edit_screen, false))
.show(fragmentManager, FRAG_TAG_DATE_PICKER)
}
}
)
}
}
}
override fun controlId() = TAG
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_DATE) {
if (resultCode == Activity.RESULT_OK) {
viewModel.setDueDate(data!!.getLongExtra(DateTimePicker.EXTRA_TIMESTAMP, 0L))
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
companion object {
const val TAG = R.string.TEA_ctrl_when_pref
private const val REQUEST_DATE = 504
private const val FRAG_TAG_DATE_PICKER = "frag_tag_date_picker"
val Long.isOverdue: Boolean
get() = if (hasDueTime(this)) {
DateTimeUtils.newDateTime(this).isBeforeNow
} else {
DateTimeUtils.newDateTime(this).endOfDay().isBeforeNow
}
}
}

@ -1,41 +0,0 @@
package org.tasks.ui
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import com.google.android.material.composethemeadapter.MdcTheme
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.compose.edit.DescriptionRow
import org.tasks.dialogs.Linkify
import org.tasks.markdown.MarkdownProvider
import org.tasks.preferences.Preferences
import org.tasks.ui.TaskEditViewModel.Companion.stripCarriageReturns
import javax.inject.Inject
@AndroidEntryPoint
class DescriptionControlSet : TaskEditControlFragment() {
@Inject lateinit var linkify: Linkify
@Inject lateinit var preferences: Preferences
@Inject lateinit var markdownProvider: MarkdownProvider
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
MdcTheme {
DescriptionRow(
text = viewModel.description.stripCarriageReturns(),
onChanged = { text -> viewModel.description = text.toString().trim { it <= ' ' } },
linkify = if (preferences.linkify) linkify else null,
markdownProvider = markdownProvider,
)
}
}
}
override fun controlId() = TAG
companion object {
const val TAG = R.string.TEA_ctrl_notes_pref
}
}

@ -1,67 +0,0 @@
package org.tasks.ui
import android.app.Activity
import android.content.Intent
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import com.google.android.material.composethemeadapter.MdcTheme
import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.activities.ListPicker
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.compose.edit.ListRow
import javax.inject.Inject
@AndroidEntryPoint
class ListFragment : TaskEditControlFragment() {
@Inject lateinit var chipProvider: ChipProvider
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
MdcTheme {
ListRow(
list = viewModel.selectedList.collectAsStateLifecycleAware().value,
colorProvider = { chipProvider.getColor(it) },
onClick = {
ListPicker.newListPicker(
viewModel.selectedList.value,
this@ListFragment,
REQUEST_CODE_SELECT_LIST
)
.show(parentFragmentManager, FRAG_TAG_GOOGLE_TASK_LIST_SELECTION)
}
)
}
}
}
override fun controlId() = TAG
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_SELECT_LIST) {
if (resultCode == Activity.RESULT_OK) {
data?.getParcelableExtra<Filter>(ListPicker.EXTRA_SELECTED_FILTER)?.let {
if (it is GtasksFilter || it is CaldavFilter) {
viewModel.selectedList.value = it
} else {
throw RuntimeException("Unhandled filter type")
}
}
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
companion object {
const val TAG = R.string.TEA_ctrl_google_task_list
private const val FRAG_TAG_GOOGLE_TASK_LIST_SELECTION = "frag_tag_google_task_list_selection"
private const val REQUEST_CODE_SELECT_LIST = 10101
}
}

@ -1,36 +0,0 @@
package org.tasks.ui
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import com.google.android.material.composethemeadapter.MdcTheme
import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.compose.edit.PriorityRow
import org.tasks.preferences.Preferences
import javax.inject.Inject
@AndroidEntryPoint
class PriorityControlSet : TaskEditControlFragment() {
@Inject lateinit var preferences: Preferences
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
MdcTheme {
PriorityRow(
priority = viewModel.priority.collectAsStateLifecycleAware().value,
onChangePriority = { viewModel.priority.value = it },
desaturate = preferences.desaturateDarkMode,
)
}
}
}
override fun controlId() = TAG
companion object {
const val TAG = R.string.TEA_ctrl_importance_pref
}
}

@ -86,75 +86,10 @@
android:gravity="center_horizontal"
android:orientation="vertical">
<FrameLayout
android:id="@+id/row_1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_2"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_3"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_4"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_5"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_6"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_7"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_8"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_9"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_10"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_11"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_12"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_13"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/row_14"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:id="@+id/comments"
@ -165,11 +100,12 @@
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<FrameLayout
android:id="@+id/comment_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="@dimen/elevation_toolbar" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/comment_bar"
android:name="org.tasks.fragments.CommentBarFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="8dp"/>
</LinearLayout>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_calendar"
android:name="org.tasks.ui.CalendarControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_files"
android:name="com.todoroo.astrid.files.FilesControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_location"
android:name="org.tasks.ui.LocationControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_reminders"
android:name="com.todoroo.astrid.ui.ReminderControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_repeat"
android:name="com.todoroo.astrid.repeats.RepeatControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<View style="@style/task_edit_row_divider"/>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_start_date"
android:name="com.todoroo.astrid.ui.StartDateControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_subtasks"
android:name="org.tasks.ui.SubtaskControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_tags"
android:name="com.todoroo.astrid.tags.TagsControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/task_edit_timer"
android:name="com.todoroo.astrid.timers.TimerControlSet"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -572,6 +572,12 @@
+| +--- androidx.compose.runtime:runtime:1.0.1 -> 1.2.0 (*)
+| +--- androidx.compose.ui:ui:1.0.1 -> 1.2.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.5.30 -> 1.7.0 (*)
++--- androidx.compose.ui:ui-viewbinding:1.2.0
+| +--- androidx.compose.ui:ui:1.2.0 (*)
+| +--- androidx.compose.ui:ui-util:1.2.0 (*)
+| +--- androidx.databinding:viewbinding:4.1.2 -> 7.2.1 (*)
+| +--- androidx.fragment:fragment-ktx:1.3.2 -> 1.4.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 1.7.0 (*)
++--- com.google.accompanist:accompanist-flowlayout:0.24.12-rc
+| +--- androidx.compose.foundation:foundation:1.2.0-rc02 -> 1.2.0 (*)
+| \--- androidx.compose.ui:ui-util:1.2.0-rc02 -> 1.2.0 (*)

@ -708,6 +708,12 @@
+| +--- androidx.compose.runtime:runtime:1.0.1 -> 1.2.0 (*)
+| +--- androidx.compose.ui:ui:1.0.1 -> 1.2.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.5.30 -> 1.7.0 (*)
++--- androidx.compose.ui:ui-viewbinding:1.2.0
+| +--- androidx.compose.ui:ui:1.2.0 (*)
+| +--- androidx.compose.ui:ui-util:1.2.0 (*)
+| +--- androidx.databinding:viewbinding:4.1.2 -> 7.2.1 (*)
+| +--- androidx.fragment:fragment-ktx:1.3.2 -> 1.4.0 (*)
+| \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 1.7.0 (*)
++--- com.google.accompanist:accompanist-flowlayout:0.24.12-rc
+| +--- androidx.compose.foundation:foundation:1.2.0-rc02 -> 1.2.0 (*)
+| \--- androidx.compose.ui:ui-util:1.2.0-rc02 -> 1.2.0 (*)

Loading…
Cancel
Save