diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c906cf26f..f4856d8f8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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}") diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt index a6caecec0..57fa8d7e2 100755 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt @@ -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(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, diff --git a/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.kt b/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.kt index 41ecc0175..a63c4f222 100644 --- a/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.kt +++ b/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.kt @@ -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 = LinkedHashMap() - private val displayOrder: List + @ActivityContext context: Context, + preferences: Preferences? +) { + val controlSetFragments: MutableMap = LinkedHashMap() + val displayOrder: List var visibleSize = 0 - fun getOrCreateFragments(fragmentManager: FragmentManager): List { - val fragments: MutableList = 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() - } - } } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/ui/CalendarControlSet.kt b/app/src/main/java/org/tasks/ui/CalendarControlSet.kt index afcc8cd81..34290b59b 100644 --- a/app/src/main/java/org/tasks/ui/CalendarControlSet.kt +++ b/app/src/main/java/org/tasks/ui/CalendarControlSet.kt @@ -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 } } diff --git a/app/src/main/java/org/tasks/ui/CreationDateControlSet.kt b/app/src/main/java/org/tasks/ui/CreationDateControlSet.kt deleted file mode 100644 index 707ffb48d..000000000 --- a/app/src/main/java/org/tasks/ui/CreationDateControlSet.kt +++ /dev/null @@ -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 - } -} diff --git a/app/src/main/java/org/tasks/ui/DeadlineControlSet.kt b/app/src/main/java/org/tasks/ui/DeadlineControlSet.kt deleted file mode 100644 index 72a6575a1..000000000 --- a/app/src/main/java/org/tasks/ui/DeadlineControlSet.kt +++ /dev/null @@ -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 - } - } -} diff --git a/app/src/main/java/org/tasks/ui/DescriptionControlSet.kt b/app/src/main/java/org/tasks/ui/DescriptionControlSet.kt deleted file mode 100644 index 087beae43..000000000 --- a/app/src/main/java/org/tasks/ui/DescriptionControlSet.kt +++ /dev/null @@ -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 - } -} diff --git a/app/src/main/java/org/tasks/ui/ListFragment.kt b/app/src/main/java/org/tasks/ui/ListFragment.kt deleted file mode 100644 index 2ed33f2b0..000000000 --- a/app/src/main/java/org/tasks/ui/ListFragment.kt +++ /dev/null @@ -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(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 - } -} diff --git a/app/src/main/java/org/tasks/ui/PriorityControlSet.kt b/app/src/main/java/org/tasks/ui/PriorityControlSet.kt deleted file mode 100644 index c19111b1f..000000000 --- a/app/src/main/java/org/tasks/ui/PriorityControlSet.kt +++ /dev/null @@ -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 - } -} diff --git a/app/src/main/res/layout/fragment_task_edit.xml b/app/src/main/res/layout/fragment_task_edit.xml index 704fa8100..4cf1c078b 100644 --- a/app/src/main/res/layout/fragment_task_edit.xml +++ b/app/src/main/res/layout/fragment_task_edit.xml @@ -86,75 +86,10 @@ android:gravity="center_horizontal" android:orientation="vertical"> - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + diff --git a/app/src/main/res/layout/task_edit_calendar.xml b/app/src/main/res/layout/task_edit_calendar.xml new file mode 100644 index 000000000..5f07258c9 --- /dev/null +++ b/app/src/main/res/layout/task_edit_calendar.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_files.xml b/app/src/main/res/layout/task_edit_files.xml new file mode 100644 index 000000000..89d289097 --- /dev/null +++ b/app/src/main/res/layout/task_edit_files.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_location.xml b/app/src/main/res/layout/task_edit_location.xml new file mode 100644 index 000000000..a35c0d297 --- /dev/null +++ b/app/src/main/res/layout/task_edit_location.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_reminders.xml b/app/src/main/res/layout/task_edit_reminders.xml new file mode 100644 index 000000000..0995c0b63 --- /dev/null +++ b/app/src/main/res/layout/task_edit_reminders.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_repeat.xml b/app/src/main/res/layout/task_edit_repeat.xml new file mode 100644 index 000000000..0d4dae343 --- /dev/null +++ b/app/src/main/res/layout/task_edit_repeat.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_row_divider.xml b/app/src/main/res/layout/task_edit_row_divider.xml deleted file mode 100644 index c7c84c700..000000000 --- a/app/src/main/res/layout/task_edit_row_divider.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/app/src/main/res/layout/task_edit_start_date.xml b/app/src/main/res/layout/task_edit_start_date.xml new file mode 100644 index 000000000..3ba11e8e5 --- /dev/null +++ b/app/src/main/res/layout/task_edit_start_date.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_subtasks.xml b/app/src/main/res/layout/task_edit_subtasks.xml new file mode 100644 index 000000000..16605842e --- /dev/null +++ b/app/src/main/res/layout/task_edit_subtasks.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_tags.xml b/app/src/main/res/layout/task_edit_tags.xml new file mode 100644 index 000000000..6ed5df0cd --- /dev/null +++ b/app/src/main/res/layout/task_edit_tags.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/task_edit_timer.xml b/app/src/main/res/layout/task_edit_timer.xml new file mode 100644 index 000000000..3f8c5f907 --- /dev/null +++ b/app/src/main/res/layout/task_edit_timer.xml @@ -0,0 +1,6 @@ + + diff --git a/deps_fdroid.txt b/deps_fdroid.txt index 6d33f3b8d..b2486d96e 100644 --- a/deps_fdroid.txt +++ b/deps_fdroid.txt @@ -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 (*) diff --git a/deps_googleplay.txt b/deps_googleplay.txt index 23e87077b..8d1676213 100644 --- a/deps_googleplay.txt +++ b/deps_googleplay.txt @@ -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 (*)