Refactoring TaskEditControlFragments

pull/3363/head
Alex Baker 9 months ago
parent 2d8df0bb67
commit 840049b206

@ -177,6 +177,7 @@ dependencies {
implementation(libs.dagger.hilt)
ksp(libs.dagger.hilt.compiler)
ksp(libs.androidx.hilt.compiler)
implementation(libs.androidx.hilt.navigation)
implementation(libs.androidx.hilt.work)
implementation(libs.androidx.datastore)

@ -8,10 +8,9 @@ package com.todoroo.astrid.files
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
@ -34,21 +33,17 @@ class FilesControlSet : TaskEditControlFragment() {
@Inject lateinit var taskAttachmentDao: TaskAttachmentDao
@Inject lateinit var preferences: Preferences
override fun createView(savedInstanceState: Bundle?) {
val task = viewModel.viewState.value.task
if (savedInstanceState == null) {
if (task.hasTransitory(TaskAttachment.KEY)) {
for (uri in (task.getTransitory<ArrayList<Uri>>(TaskAttachment.KEY))!!) {
@Composable
override fun Content() {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
LaunchedEffect(Unit) {
if (viewState.task.hasTransitory(TaskAttachment.KEY)) {
for (uri in (viewState.task.getTransitory<ArrayList<Uri>>(TaskAttachment.KEY))!!) {
newAttachment(uri)
}
}
}
}
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
val context = LocalContext.current
AttachmentRow(
attachments = viewState.attachments,
openAttachment = {
@ -69,7 +64,6 @@ class FilesControlSet : TaskEditControlFragment() {
},
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == AddAttachmentDialog.REQUEST_CAMERA || requestCode == AddAttachmentDialog.REQUEST_AUDIO) {

@ -7,12 +7,9 @@ package com.todoroo.astrid.repeats
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import net.fortuna.ical4j.model.Recur
import net.fortuna.ical4j.model.WeekDay
@ -67,18 +64,13 @@ class RepeatControlSet : TaskEditControlFragment() {
}
}
override fun createView(savedInstanceState: Bundle?) {
lifecycleScope.launchWhenResumed {
viewModel.dueDate.collect {
@Composable
override fun Content() {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
val dueDate = viewModel.dueDate.collectAsStateWithLifecycle().value
LaunchedEffect(dueDate) {
onDueDateChanged()
}
}
}
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
RepeatRow(
recurrence = viewState.task.recurrence?.let { repeatRuleToString.toString(it) },
repeatFrom = viewState.task.repeatFrom,
@ -88,7 +80,7 @@ class RepeatControlSet : TaskEditControlFragment() {
target = this@RepeatControlSet,
rc = REQUEST_RECURRENCE,
rrule = viewState.task.recurrence,
dueDate = viewModel.dueDate.value,
dueDate = dueDate,
accountType = accountType,
)
.show(parentFragmentManager, FRAG_TAG_BASIC_RECURRENCE)
@ -96,7 +88,6 @@ class RepeatControlSet : TaskEditControlFragment() {
onRepeatFromChanged = { viewModel.setRepeatFrom(it) }
)
}
}
companion object {
val TAG = R.string.TEA_ctrl_repeat_pref

@ -2,9 +2,7 @@ package com.todoroo.astrid.tags
import android.app.Activity
import android.content.Intent
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.core.content.IntentCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import dagger.hilt.android.AndroidEntryPoint
@ -22,25 +20,23 @@ import javax.inject.Inject
class TagsControlSet : TaskEditControlFragment() {
@Inject lateinit var chipProvider: ChipProvider
private fun onRowClick() {
}
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
@Composable
override fun Content() {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
TagsRow(
tags = viewState.tags,
colorProvider = { chipProvider.getColor(it) },
onClick = {
val intent = Intent(context, TagPickerActivity::class.java)
intent.putParcelableArrayListExtra(TagPickerActivity.EXTRA_SELECTED, ArrayList(viewState.tags))
intent.putParcelableArrayListExtra(
TagPickerActivity.EXTRA_SELECTED,
ArrayList(viewState.tags)
)
startActivityForResult(intent, REQUEST_TAG_PICKER_ACTIVITY)
},
onClear = { viewModel.setTags(viewState.tags.minus(it)) },
)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_TAG_PICKER_ACTIVITY) {

@ -6,12 +6,11 @@
package com.todoroo.astrid.timers
import android.app.Activity
import android.os.Bundle
import android.text.format.DateUtils
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.ui.TimeDurationControlSet
@ -45,14 +44,6 @@ class TimerControlSet : TaskEditControlFragment() {
private var dialog: AlertDialog? = null
private lateinit var dialogView: View
override fun createView(savedInstanceState: Bundle?) {
dialogView = activity.layoutInflater.inflate(R.layout.control_set_timers_dialog, null)
estimated = TimeDurationControlSet(activity, dialogView, R.id.estimatedDuration, theme)
elapsed = TimeDurationControlSet(activity, dialogView, R.id.elapsedDuration, theme)
estimated.setTimeDuration(viewModel.estimatedSeconds.value)
elapsed.setTimeDuration(viewModel.elapsedSeconds.value)
}
private fun onRowClick() {
if (dialog == null) {
dialog = buildDialog()
@ -86,9 +77,15 @@ class TimerControlSet : TaskEditControlFragment() {
}
}
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
@Composable
override fun Content() {
LaunchedEffect(Unit) {
dialogView = activity.layoutInflater.inflate(R.layout.control_set_timers_dialog, null)
estimated = TimeDurationControlSet(activity, dialogView, R.id.estimatedDuration, theme)
elapsed = TimeDurationControlSet(activity, dialogView, R.id.elapsedDuration, theme)
estimated.setTimeDuration(viewModel.estimatedSeconds.value)
elapsed.setTimeDuration(viewModel.elapsedSeconds.value)
}
TimerRow(
started = viewModel.timerStarted.collectAsStateWithLifecycle().value,
estimated = viewModel.estimatedSeconds.collectAsStateWithLifecycle().value,
@ -97,7 +94,6 @@ class TimerControlSet : TaskEditControlFragment() {
onClick = this@TimerControlSet::onRowClick,
)
}
}
private fun timerActive() = viewModel.timerStarted.value > 0

@ -5,15 +5,14 @@ import android.app.Activity
import android.app.Activity.RESULT_OK
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionStatus
@ -39,42 +38,24 @@ class ReminderControlSet : TaskEditControlFragment() {
@Inject lateinit var activity: Activity
@Inject lateinit var dialogBuilder: DialogBuilder
private val ringMode = mutableStateOf(0)
override fun createView(savedInstanceState: Bundle?) {
when {
viewModel.ringNonstop -> setRingMode(2)
viewModel.ringFiveTimes -> setRingMode(1)
else -> setRingMode(0)
}
}
private fun onClickRingType() {
val modes = resources.getStringArray(R.array.reminder_ring_modes)
val ringMode = when {
viewModel.ringNonstop -> 2
viewModel.ringFiveTimes -> 1
else -> 0
}
dialogBuilder
.newDialog()
.setSingleChoiceItems(modes, ringMode) { dialog: DialogInterface, which: Int ->
setRingMode(which)
dialog.dismiss()
}
.show()
}
private val ringMode = mutableIntStateOf(0)
private fun setRingMode(ringMode: Int) {
viewModel.ringNonstop = ringMode == 2
viewModel.ringFiveTimes = ringMode == 1
this.ringMode.value = ringMode
this.ringMode.intValue = ringMode
}
@OptIn(ExperimentalPermissionsApi::class)
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
@Composable
override fun Content() {
LaunchedEffect(Unit) {
when {
viewModel.ringNonstop -> setRingMode(2)
viewModel.ringFiveTimes -> setRingMode(1)
else -> setRingMode(0)
}
}
val ringMode by remember { this@ReminderControlSet.ringMode }
val hasReminderPermissions by rememberReminderPermissionState()
val notificationPermissions = if (AndroidUtilities.atLeastTiramisu()) {
@ -100,6 +81,7 @@ class ReminderControlSet : TaskEditControlFragment() {
viewModel.addAlarm(Alarm(time = timestamp, type = TYPE_DATE_TIME))
}
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
val context = LocalContext.current
AlarmRow(
alarms = viewState.alarms,
hasNotificationPermissions = hasReminderPermissions &&
@ -113,7 +95,21 @@ class ReminderControlSet : TaskEditControlFragment() {
},
ringMode = ringMode,
addAlarm = viewModel::addAlarm,
openRingType = this@ReminderControlSet::onClickRingType,
openRingType = {
val modes = resources.getStringArray(R.array.reminder_ring_modes)
val selectedIndex = when {
viewModel.ringNonstop -> 2
viewModel.ringFiveTimes -> 1
else -> 0
}
dialogBuilder
.newDialog()
.setSingleChoiceItems(modes, selectedIndex) { dialog: DialogInterface, which: Int ->
setRingMode(which)
dialog.dismiss()
}
.show()
},
deleteAlarm = viewModel::removeAlarm,
pickDateAndTime = { replace ->
val timestamp = replace?.takeIf { it.type == TYPE_DATE_TIME }?.time
@ -126,7 +122,6 @@ class ReminderControlSet : TaskEditControlFragment() {
}
)
}
}
companion object {
val TAG = R.string.TEA_ctrl_reminders_pref

@ -3,12 +3,10 @@ package com.todoroo.astrid.ui
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.runBlocking
import org.tasks.R
@ -34,31 +32,23 @@ class StartDateControlSet : TaskEditControlFragment() {
private val vm: StartDateViewModel by viewModels()
override fun createView(savedInstanceState: Bundle?) {
if (savedInstanceState == null) {
@Composable
override fun Content() {
LaunchedEffect(Unit) {
vm.init(
dueDate = viewModel.dueDate.value,
startDate = viewModel.startDate.value,
isNew = viewModel.viewState.value.isNew
)
}
lifecycleScope.launchWhenResumed {
viewModel.dueDate.collect {
applySelected()
}
}
}
override fun bind(parent: ViewGroup?) =
(parent as ComposeView).apply {
setContent {
val dueDate = viewModel.dueDate.collectAsStateWithLifecycle().value
val selectedDay = vm.selectedDay.collectAsStateWithLifecycle().value
val selectedTime = vm.selectedTime.collectAsStateWithLifecycle().value
StartDateRow(
startDate = viewModel.startDate.collectAsStateWithLifecycle().value,
selectedDay = selectedDay,
selectedTime = selectedTime,
hasDueDate = viewModel.dueDate.collectAsStateWithLifecycle().value > 0,
hasDueDate = dueDate > 0,
printDate = {
runBlocking {
getRelativeDateTime(
@ -86,6 +76,9 @@ class StartDateControlSet : TaskEditControlFragment() {
}
}
)
LaunchedEffect(dueDate) {
applySelected()
}
}

@ -4,11 +4,9 @@ import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.CalendarContract
import android.view.View
import android.view.ViewGroup
import android.widget.Toast.LENGTH_SHORT
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.ComposeView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.todoroo.astrid.activity.TaskEditFragment
import dagger.hilt.android.AndroidEntryPoint
@ -42,9 +40,8 @@ class CalendarControlSet : TaskEditControlFragment() {
}
}
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
@Composable
override fun Content() {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
CalendarRow(
eventUri = viewModel.eventUri.collectAsStateWithLifecycle().value,
@ -73,7 +70,6 @@ class CalendarControlSet : TaskEditControlFragment() {
}
)
}
}
private fun openCalendarEvent() {
val cr = activity.contentResolver

@ -4,9 +4,7 @@ import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Parcelable
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.core.content.IntentCompat
import androidx.core.util.Pair
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -53,9 +51,8 @@ class LocationControlSet : TaskEditControlFragment() {
}
@OptIn(ExperimentalPermissionsApi::class)
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
@Composable
override fun Content() {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
val hasPermissions =
rememberMultiplePermissionsState(permissions = backgroundPermissions())
@ -103,7 +100,6 @@ class LocationControlSet : TaskEditControlFragment() {
}
)
}
}
private fun openWebsite() {
viewModel.viewState.value.location?.let { context?.openUri(it.url) }

@ -1,12 +1,10 @@
package org.tasks.ui
import android.app.Activity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.todoroo.astrid.activity.MainActivityViewModel
@ -39,20 +37,17 @@ class SubtaskControlSet : TaskEditControlFragment() {
@Inject lateinit var preferences: Preferences
@Inject lateinit var firebase: Firebase
private lateinit var listViewModel: TaskListViewModel
private val mainViewModel: MainActivityViewModel by activityViewModels()
override fun createView(savedInstanceState: Bundle?) {
viewModel.viewState.value.task.takeIf { it.id > 0 }?.let {
listViewModel.setFilter(SubtaskFilter(it.id))
@Composable
override fun Content() {
val listViewModel: TaskListViewModel = hiltViewModel()
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
LaunchedEffect(viewState.task) {
if (viewState.task.id > 0) {
listViewModel.setFilter(SubtaskFilter(viewState.task.id))
}
}
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
listViewModel = ViewModelProvider(requireParentFragment())[TaskListViewModel::class.java]
setContent {
val viewState = viewModel.viewState.collectAsStateWithLifecycle().value
val originalState = viewModel.originalState.collectAsStateWithLifecycle().value
SubtaskRow(
originalFilter = originalState.list,
@ -87,7 +82,6 @@ class SubtaskControlSet : TaskEditControlFragment() {
deleteSubtask = { viewModel.setSubtasks(viewState.newSubtasks - it) },
)
}
}
private fun openSubtask(task: Task) = lifecycleScope.launch {
mainViewModel.setTask(task)

@ -2,11 +2,11 @@ package org.tasks.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.runtime.Composable
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.fragment.compose.content
import androidx.hilt.navigation.compose.hiltViewModel
abstract class TaskEditControlFragment : Fragment() {
lateinit var viewModel: TaskEditViewModel
@ -15,15 +15,11 @@ abstract class TaskEditControlFragment : Fragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val composeView = ComposeView(requireActivity())
viewModel = ViewModelProvider(requireParentFragment())[TaskEditViewModel::class.java]
bind(composeView)
createView(savedInstanceState)
return composeView
) = content {
viewModel = hiltViewModel<TaskEditViewModel>(viewModelStoreOwner = requireParentFragment())
Content()
}
abstract fun bind(parent: ViewGroup?): View
protected open fun createView(savedInstanceState: Bundle?) {}
@Composable
abstract fun Content()
}

@ -591,7 +591,7 @@ class TaskEditViewModel @Inject constructor(
}
init {
viewModelScope.launch {
runBlocking {
val attachments = async {
taskAttachmentDao
.getAttachments(task.id)

@ -78,6 +78,7 @@ androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscree
androidx-datastore = { module = "androidx.datastore:datastore-preferences", version = "1.1.2" }
androidx-fragment-compose = { module = "androidx.fragment:fragment-compose", version = "1.8.6" }
androidx-hilt-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hilt" }
androidx-hilt-navigation = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hilt" }
androidx-hilt-work = { module = "androidx.hilt:hilt-work", version.ref = "hilt" }
androidx-junit = { module = "androidx.test.ext:junit", version.ref = "junit" }
androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "lifecycle" }

Loading…
Cancel
Save