mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
570 lines
22 KiB
Kotlin
570 lines
22 KiB
Kotlin
/*
|
|
* Copyright (c) 2012 Todoroo Inc
|
|
*
|
|
* See the file "LICENSE" for the full license governing this code.
|
|
*/
|
|
package com.todoroo.astrid.activity
|
|
|
|
import android.app.Activity
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.graphics.Paint
|
|
import android.os.Bundle
|
|
import android.view.LayoutInflater
|
|
import android.view.MenuItem
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.view.inputmethod.EditorInfo
|
|
import android.view.inputmethod.InputMethodManager
|
|
import androidx.activity.addCallback
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
import androidx.appcompat.content.res.AppCompatResources
|
|
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.input.pointer.PointerEventPass
|
|
import androidx.compose.ui.input.pointer.pointerInput
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.compose.ui.viewinterop.AndroidViewBinding
|
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
|
import androidx.core.os.BundleCompat
|
|
import androidx.core.widget.addTextChangedListener
|
|
import androidx.fragment.app.Fragment
|
|
import androidx.fragment.app.viewModels
|
|
import androidx.lifecycle.lifecycleScope
|
|
import com.google.android.material.appbar.AppBarLayout
|
|
import com.google.android.material.appbar.AppBarLayout.Behavior.DragCallback
|
|
import com.google.android.material.composethemeadapter.MdcTheme
|
|
import com.todoroo.andlib.utility.AndroidUtilities.atLeastOreoMR1
|
|
import com.todoroo.andlib.utility.DateUtilities
|
|
import com.todoroo.astrid.dao.TaskDao
|
|
import com.todoroo.astrid.data.Task
|
|
import com.todoroo.astrid.files.FilesControlSet
|
|
import com.todoroo.astrid.repeats.RepeatControlSet
|
|
import com.todoroo.astrid.tags.TagsControlSet
|
|
import com.todoroo.astrid.timers.TimerControlSet
|
|
import com.todoroo.astrid.ui.ReminderControlSet
|
|
import com.todoroo.astrid.ui.StartDateControlSet
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import kotlinx.coroutines.flow.launchIn
|
|
import kotlinx.coroutines.flow.onEach
|
|
import kotlinx.coroutines.flow.update
|
|
import kotlinx.coroutines.launch
|
|
import org.tasks.R
|
|
import org.tasks.Strings.isNullOrEmpty
|
|
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.CommentsRow
|
|
import org.tasks.compose.edit.DescriptionRow
|
|
import org.tasks.compose.edit.DueDateRow
|
|
import org.tasks.compose.edit.InfoRow
|
|
import org.tasks.compose.edit.ListRow
|
|
import org.tasks.compose.edit.PriorityRow
|
|
import org.tasks.data.UserActivityDao
|
|
import org.tasks.databinding.FragmentTaskEditBinding
|
|
import org.tasks.databinding.TaskEditCalendarBinding
|
|
import org.tasks.databinding.TaskEditFilesBinding
|
|
import org.tasks.databinding.TaskEditLocationBinding
|
|
import org.tasks.databinding.TaskEditRemindersBinding
|
|
import org.tasks.databinding.TaskEditRepeatBinding
|
|
import org.tasks.databinding.TaskEditStartDateBinding
|
|
import org.tasks.databinding.TaskEditSubtasksBinding
|
|
import org.tasks.databinding.TaskEditTagsBinding
|
|
import org.tasks.databinding.TaskEditTimerBinding
|
|
import org.tasks.date.DateTimeUtils.newDateTime
|
|
import org.tasks.dialogs.DateTimePicker
|
|
import org.tasks.dialogs.DialogBuilder
|
|
import org.tasks.dialogs.FilterPicker.Companion.newFilterPicker
|
|
import org.tasks.dialogs.FilterPicker.Companion.setFilterPickerResultListener
|
|
import org.tasks.dialogs.Linkify
|
|
import org.tasks.extensions.hideKeyboard
|
|
import org.tasks.files.FileHelper
|
|
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.play.PlayServices
|
|
import org.tasks.preferences.Preferences
|
|
import org.tasks.ui.CalendarControlSet
|
|
import org.tasks.ui.ChipProvider
|
|
import org.tasks.ui.LocationControlSet
|
|
import org.tasks.ui.SubtaskControlSet
|
|
import org.tasks.ui.TaskEditEvent
|
|
import org.tasks.ui.TaskEditEventBus
|
|
import org.tasks.ui.TaskEditViewModel
|
|
import org.tasks.ui.TaskEditViewModel.Companion.stripCarriageReturns
|
|
import java.time.format.FormatStyle
|
|
import java.util.Locale
|
|
import javax.inject.Inject
|
|
import kotlin.math.abs
|
|
|
|
@AndroidEntryPoint
|
|
class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|
@Inject lateinit var taskDao: TaskDao
|
|
@Inject lateinit var userActivityDao: UserActivityDao
|
|
@Inject lateinit var notificationManager: NotificationManager
|
|
@Inject lateinit var dialogBuilder: DialogBuilder
|
|
@Inject lateinit var context: Activity
|
|
@Inject lateinit var taskEditControlSetFragmentManager: TaskEditControlSetFragmentManager
|
|
@Inject lateinit var preferences: Preferences
|
|
@Inject lateinit var firebase: Firebase
|
|
@Inject lateinit var linkify: Linkify
|
|
@Inject lateinit var markdownProvider: MarkdownProvider
|
|
@Inject lateinit var taskEditEventBus: TaskEditEventBus
|
|
@Inject lateinit var locale: Locale
|
|
@Inject lateinit var chipProvider: ChipProvider
|
|
@Inject lateinit var playServices: PlayServices
|
|
|
|
val editViewModel: TaskEditViewModel by viewModels()
|
|
lateinit var binding: FragmentTaskEditBinding
|
|
private var showKeyboard = false
|
|
private val beastMode =
|
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
|
activity?.recreate()
|
|
}
|
|
|
|
val task: Task?
|
|
get() = BundleCompat.getParcelable(requireArguments(), EXTRA_TASK, Task::class.java)
|
|
|
|
override fun onCreateView(
|
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
|
requireActivity().onBackPressedDispatcher.addCallback(owner = viewLifecycleOwner) {
|
|
if (preferences.backButtonSavesTask()) {
|
|
lifecycleScope.launch {
|
|
save()
|
|
}
|
|
} else {
|
|
discardButtonClick()
|
|
}
|
|
}
|
|
if (atLeastOreoMR1()) {
|
|
activity?.setShowWhenLocked(preferences.showEditScreenWithoutUnlock)
|
|
}
|
|
|
|
binding = FragmentTaskEditBinding.inflate(inflater)
|
|
val view: View = binding.root
|
|
val model = editViewModel.task
|
|
val toolbar = binding.toolbar
|
|
toolbar.navigationIcon = AppCompatResources.getDrawable(
|
|
context,
|
|
if (editViewModel.isReadOnly)
|
|
R.drawable.ic_outline_arrow_back_24px
|
|
else
|
|
R.drawable.ic_outline_save_24px
|
|
)
|
|
toolbar.setNavigationOnClickListener {
|
|
lifecycleScope.launch {
|
|
save()
|
|
}
|
|
}
|
|
val backButtonSavesTask = preferences.backButtonSavesTask()
|
|
toolbar.setNavigationContentDescription(
|
|
when {
|
|
editViewModel.isReadOnly -> R.string.back
|
|
backButtonSavesTask -> R.string.discard
|
|
else -> R.string.save
|
|
}
|
|
)
|
|
toolbar.inflateMenu(R.menu.menu_task_edit_fragment)
|
|
val menu = toolbar.menu
|
|
val delete = menu.findItem(R.id.menu_delete)
|
|
delete.isVisible = !model.isNew && editViewModel.isWritable
|
|
delete.setShowAsAction(
|
|
if (backButtonSavesTask) MenuItem.SHOW_AS_ACTION_NEVER else MenuItem.SHOW_AS_ACTION_IF_ROOM)
|
|
val discard = menu.findItem(R.id.menu_discard)
|
|
discard.isVisible = backButtonSavesTask && editViewModel.isWritable
|
|
discard.setShowAsAction(
|
|
if (model.isNew) MenuItem.SHOW_AS_ACTION_IF_ROOM else MenuItem.SHOW_AS_ACTION_NEVER)
|
|
if (savedInstanceState == null) {
|
|
showKeyboard = model.isNew && isNullOrEmpty(model.title)
|
|
}
|
|
val params = binding.appbarlayout.layoutParams as CoordinatorLayout.LayoutParams
|
|
params.behavior = AppBarLayout.Behavior()
|
|
val behavior = params.behavior as AppBarLayout.Behavior?
|
|
behavior!!.setDragCallback(object : DragCallback() {
|
|
override fun canDrag(appBarLayout: AppBarLayout): Boolean {
|
|
return false
|
|
}
|
|
})
|
|
toolbar.setOnMenuItemClickListener(this)
|
|
val title = binding.title
|
|
val textWatcher = markdownProvider.markdown(preferences.linkify).textWatcher(title)
|
|
title.addTextChangedListener(
|
|
onTextChanged = { _, _, _, _ ->
|
|
editViewModel.title = title.text.toString().trim { it <= ' ' }
|
|
},
|
|
afterTextChanged = {
|
|
textWatcher?.invoke(it)
|
|
}
|
|
)
|
|
title.setOnEditorActionListener { _, actionId, _ ->
|
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
|
lifecycleScope.launch {
|
|
save()
|
|
}
|
|
true
|
|
} else false
|
|
}
|
|
title.setText(model.title)
|
|
title.setHorizontallyScrolling(false)
|
|
title.maxLines = 5
|
|
if (editViewModel.isReadOnly) {
|
|
title.isFocusable = false
|
|
title.isFocusableInTouchMode = false
|
|
title.isCursorVisible = false
|
|
}
|
|
if (
|
|
model.isNew ||
|
|
preferences.getBoolean(R.string.p_hide_check_button, false) ||
|
|
editViewModel.isReadOnly
|
|
) {
|
|
binding.fab.visibility = View.INVISIBLE
|
|
} else if (editViewModel.completed) {
|
|
title.paintFlags = title.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
|
|
binding.fab.setImageResource(R.drawable.ic_outline_check_box_outline_blank_24px)
|
|
}
|
|
binding.fab.setOnClickListener {
|
|
if (editViewModel.completed) {
|
|
editViewModel.completed = false
|
|
title.paintFlags = title.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
|
|
binding.fab.setImageResource(R.drawable.ic_outline_check_box_24px)
|
|
} else {
|
|
editViewModel.completed = true
|
|
lifecycleScope.launch {
|
|
save()
|
|
}
|
|
}
|
|
}
|
|
binding.appbarlayout.addOnOffsetChangedListener { appBarLayout, verticalOffset ->
|
|
if (verticalOffset == 0) {
|
|
title.visibility = View.VISIBLE
|
|
binding.collapsingtoolbarlayout.isTitleEnabled = false
|
|
} else if (abs(verticalOffset) < appBarLayout.totalScrollRange) {
|
|
title.visibility = View.INVISIBLE
|
|
binding.collapsingtoolbarlayout.title = title.text
|
|
binding.collapsingtoolbarlayout.isTitleEnabled = true
|
|
}
|
|
}
|
|
if (!model.isNew) {
|
|
lifecycleScope.launch {
|
|
notificationManager.cancel(model.id)
|
|
}
|
|
if (preferences.linkify) {
|
|
linkify.linkify(title)
|
|
}
|
|
}
|
|
binding.composeView.setContent {
|
|
MdcTheme {
|
|
Column(modifier = Modifier.gesturesDisabled(editViewModel.isReadOnly)) {
|
|
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())
|
|
}
|
|
}
|
|
if (preferences.getBoolean(R.string.p_show_task_edit_comments, false)) {
|
|
Comments()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
childFragmentManager.setFilterPickerResultListener(this) { filter ->
|
|
editViewModel.selectedList.update { filter }
|
|
}
|
|
return view
|
|
}
|
|
|
|
override fun onDestroyView() {
|
|
super.onDestroyView()
|
|
if (atLeastOreoMR1()) {
|
|
activity?.setShowWhenLocked(false)
|
|
}
|
|
}
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
taskEditEventBus
|
|
.onEach(this::process)
|
|
.launchIn(viewLifecycleOwner.lifecycleScope)
|
|
}
|
|
|
|
private suspend fun process(event: TaskEditEvent) {
|
|
when (event) {
|
|
is TaskEditEvent.Discard ->
|
|
if (event.id == editViewModel.task.id) {
|
|
editViewModel.discard()
|
|
}
|
|
}
|
|
}
|
|
|
|
@OptIn(ExperimentalAnimationApi::class)
|
|
private fun showBeastModeHint() {
|
|
binding.banner.setContent {
|
|
var visible by rememberSaveable { mutableStateOf(true) }
|
|
val context = LocalContext.current
|
|
MdcTheme {
|
|
BeastModeBanner(
|
|
visible,
|
|
showSettings = {
|
|
visible = false
|
|
preferences.shownBeastModeHint = true
|
|
beastMode.launch(Intent(context, BeastModePreferences::class.java))
|
|
firebase.logEvent(R.string.event_banner_beast, R.string.param_click to true)
|
|
},
|
|
dismiss = {
|
|
visible = false
|
|
preferences.shownBeastModeHint = true
|
|
firebase.logEvent(R.string.event_banner_beast, R.string.param_click to false)
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
if (showKeyboard) {
|
|
binding.title.requestFocus()
|
|
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
imm.showSoftInput(binding.title, InputMethodManager.SHOW_IMPLICIT)
|
|
}
|
|
if (!preferences.shownBeastModeHint) {
|
|
showBeastModeHint()
|
|
}
|
|
}
|
|
|
|
override fun onMenuItemClick(item: MenuItem): Boolean {
|
|
activity?.hideKeyboard()
|
|
if (item.itemId == R.id.menu_delete) {
|
|
deleteButtonClick()
|
|
return true
|
|
} else if (item.itemId == R.id.menu_discard) {
|
|
discardButtonClick()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
suspend fun save(remove: Boolean = true) {
|
|
editViewModel.save(remove)
|
|
activity?.let { playServices.requestReview(it) }
|
|
}
|
|
|
|
private fun discardButtonClick() {
|
|
if (editViewModel.hasChanges()) {
|
|
dialogBuilder
|
|
.newDialog(R.string.discard_confirmation)
|
|
.setPositiveButton(R.string.keep_editing, null)
|
|
.setNegativeButton(R.string.discard) { _, _ -> discard() }
|
|
.show()
|
|
} else {
|
|
discard()
|
|
}
|
|
}
|
|
|
|
private fun deleteButtonClick() {
|
|
dialogBuilder
|
|
.newDialog(R.string.DLG_delete_this_task_question)
|
|
.setPositiveButton(R.string.ok) { _, _ -> delete() }
|
|
.setNegativeButton(R.string.cancel, null)
|
|
.show()
|
|
}
|
|
|
|
private fun discard() = lifecycleScope.launch {
|
|
editViewModel.discard()
|
|
}
|
|
|
|
private fun delete() = lifecycleScope.launch {
|
|
editViewModel.delete()
|
|
}
|
|
|
|
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_PICK_CALENDAR -> {
|
|
if (resultCode == Activity.RESULT_OK) {
|
|
editViewModel.selectedCalendar.value =
|
|
data!!.getStringExtra(CalendarPicker.EXTRA_CALENDAR_ID)
|
|
}
|
|
}
|
|
else -> super.onActivityResult(requestCode, resultCode, data)
|
|
}
|
|
}
|
|
|
|
@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(
|
|
target = this@TaskEditFragment,
|
|
rc = REQUEST_DATE,
|
|
current = editViewModel.dueDate.value,
|
|
autoClose = preferences.getBoolean(
|
|
R.string.p_auto_dismiss_datetime_edit_screen,
|
|
false
|
|
),
|
|
hideNoDate = editViewModel.recurrence.value?.isNotBlank() == true,
|
|
)
|
|
.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() {
|
|
val list = editViewModel.selectedList.collectAsStateLifecycleAware().value
|
|
ListRow(
|
|
list = list,
|
|
colorProvider = { chipProvider.getColor(it) },
|
|
onClick = {
|
|
newFilterPicker(list, true)
|
|
.show(
|
|
childFragmentManager,
|
|
FRAG_TAG_GOOGLE_TASK_LIST_SELECTION
|
|
)
|
|
}
|
|
)
|
|
}
|
|
|
|
@Composable
|
|
fun CreationRow() {
|
|
InfoRow(
|
|
creationDate = editViewModel.creationDate,
|
|
modificationDate = editViewModel.modificationDate,
|
|
completionDate = editViewModel.completionDate,
|
|
locale = locale,
|
|
)
|
|
}
|
|
|
|
@Composable
|
|
fun Comments() {
|
|
CommentsRow(
|
|
comments = userActivityDao
|
|
.watchComments(editViewModel.task.uuid)
|
|
.collectAsStateLifecycleAware(emptyList())
|
|
.value,
|
|
deleteComment = {
|
|
lifecycleScope.launch {
|
|
userActivityDao.delete(it)
|
|
}
|
|
},
|
|
openImage = { FileHelper.startActionView(requireActivity(), it) }
|
|
)
|
|
}
|
|
|
|
companion object {
|
|
const val EXTRA_TASK = "extra_task"
|
|
|
|
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"
|
|
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,
|
|
): TaskEditFragment {
|
|
val taskEditFragment = TaskEditFragment()
|
|
val arguments = Bundle()
|
|
arguments.putParcelable(EXTRA_TASK, task)
|
|
taskEditFragment.arguments = arguments
|
|
return taskEditFragment
|
|
}
|
|
|
|
fun Modifier.gesturesDisabled(disabled: Boolean = true) =
|
|
if (disabled) {
|
|
pointerInput(Unit) {
|
|
awaitPointerEventScope {
|
|
while (true) {
|
|
awaitPointerEvent(pass = PointerEventPass.Initial)
|
|
.changes
|
|
.filter { it.position == it.previousPosition }
|
|
.forEach { it.consume() }
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
this
|
|
}
|
|
}
|
|
} |