Convert edit screen to use compose scaffold

Remove collapsing toolbar and fab
pull/3145/head
Alex Baker 1 year ago
parent 82ceda7108
commit bfcff55854

@ -1,48 +1,44 @@
/*
* 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.compose.BackHandler
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.material3.Divider
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Clear
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Save
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar
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.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
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.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.Behavior.DragCallback
import com.todoroo.andlib.utility.AndroidUtilities.atLeastOreoMR1
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.files.FilesControlSet
@ -75,8 +71,8 @@ import org.tasks.data.dao.UserActivityDao
import org.tasks.data.entity.Alarm
import org.tasks.data.entity.TagData
import org.tasks.data.entity.Task
import org.tasks.databinding.FragmentTaskEditBinding
import org.tasks.databinding.TaskEditCalendarBinding
import org.tasks.databinding.TaskEditCommentBarBinding
import org.tasks.databinding.TaskEditFilesBinding
import org.tasks.databinding.TaskEditLocationBinding
import org.tasks.databinding.TaskEditRemindersBinding
@ -106,6 +102,7 @@ import org.tasks.notifications.NotificationManager
import org.tasks.play.PlayServices
import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import org.tasks.themes.Theme
import org.tasks.ui.CalendarControlSet
import org.tasks.ui.ChipProvider
import org.tasks.ui.LocationControlSet
@ -116,10 +113,9 @@ import org.tasks.ui.TaskEditViewModel
import org.tasks.ui.TaskEditViewModel.Companion.stripCarriageReturns
import java.util.Locale
import javax.inject.Inject
import kotlin.math.abs
@AndroidEntryPoint
class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
class TaskEditFragment : Fragment() {
@Inject lateinit var taskDao: TaskDao
@Inject lateinit var userActivityDao: UserActivityDao
@Inject lateinit var notificationManager: NotificationManager
@ -134,9 +130,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
@Inject lateinit var locale: Locale
@Inject lateinit var chipProvider: ChipProvider
@Inject lateinit var playServices: PlayServices
@Inject lateinit var theme: Theme
val editViewModel: TaskEditViewModel by viewModels()
lateinit var binding: FragmentTaskEditBinding
private val editViewModel: TaskEditViewModel by viewModels()
private var showKeyboard = false
private val beastMode =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
@ -149,136 +145,97 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
val task: Task?
get() = BundleCompat.getParcelable(requireArguments(), EXTRA_TASK, Task::class.java)
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class)
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 {
if (!model.isNew) {
lifecycleScope.launch {
save()
}
notificationManager.cancel(model.id)
}
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) {
val backButtonSavesTask = preferences.backButtonSavesTask()
val view = ComposeView(context).apply {
setContent {
BackHandler {
if (backButtonSavesTask) {
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()
discardButtonClick()
}
}
TasksTheme(theme = theme.themeBase.index,) {
Scaffold(
topBar = {
TopAppBar(
navigationIcon = {
IconButton(
onClick = {
when {
editViewModel.isReadOnly -> activity?.onBackPressed()
backButtonSavesTask -> discardButtonClick()
else -> 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
}
) {
Icon(
imageVector = when {
editViewModel.isReadOnly -> Icons.AutoMirrored.Outlined.ArrowBack
backButtonSavesTask -> Icons.Outlined.Clear
else -> Icons.Outlined.Save
},
contentDescription = when {
editViewModel.isReadOnly -> stringResource(R.string.back)
backButtonSavesTask -> stringResource(R.string.discard)
else -> stringResource(R.string.save)
}
if (!model.isNew) {
lifecycleScope.launch {
notificationManager.cancel(model.id)
)
}
if (preferences.linkify) {
linkify.linkify(title)
},
title = {},
actions = {
if (backButtonSavesTask && editViewModel.isWritable) {
IconButton(onClick = { discardButtonClick() }) {
Icon(
imageVector = Icons.Outlined.Clear,
contentDescription = stringResource(R.string.menu_discard_changes),
)
}
}
binding.composeView.setContent {
TasksTheme {
Column(modifier = Modifier.gesturesDisabled(editViewModel.isReadOnly)) {
if (!editViewModel.isNew && editViewModel.isWritable) {
IconButton(onClick = { deleteButtonClick() }) {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = stringResource(R.string.delete_task),
)
}
}
},
)
},
bottomBar = {
if (preferences.getBoolean(R.string.p_show_task_edit_comments, false)) {
AndroidViewBinding(TaskEditCommentBarBinding::inflate)
}
},
) { paddingValues ->
Column(
modifier = Modifier
.gesturesDisabled(editViewModel.isReadOnly)
.padding(paddingValues)
.fillMaxSize()
.verticalScroll(rememberScrollState()),
) {
TitleRow(requestFocus = showKeyboard)
HorizontalDivider()
taskEditControlSetFragmentManager.displayOrder.forEachIndexed { index, tag ->
if (index < taskEditControlSetFragmentManager.visibleSize) {
// TODO: remove ui-viewbinding library when these are all migrated
@ -303,12 +260,26 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
SubtaskControlSet.TAG -> AndroidViewBinding(TaskEditSubtasksBinding::inflate)
else -> throw IllegalArgumentException("Unknown row: $tag")
}
Divider(modifier = Modifier.fillMaxWidth())
HorizontalDivider()
}
}
if (preferences.getBoolean(R.string.p_show_task_edit_comments, false)) {
Comments()
}
val showBeastModeHint = editViewModel.showBeastModeHint.collectAsStateWithLifecycle().value
val context = LocalContext.current
BeastModeBanner(
showBeastModeHint,
showSettings = {
editViewModel.hideBeastModeHint(click = true)
beastMode.launch(Intent(context, BeastModePreferences::class.java))
},
dismiss = {
editViewModel.hideBeastModeHint(click = false)
}
)
}
}
}
}
}
@ -337,60 +308,13 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
}
@OptIn(ExperimentalAnimationApi::class)
private fun showBeastModeHint() {
binding.banner.setContent {
var visible by rememberSaveable { mutableStateOf(true) }
val context = LocalContext.current
TasksTheme {
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() {
activity?.hideKeyboard()
if (editViewModel.hasChanges()) {
dialogBuilder
.newDialog(R.string.discard_confirmation)
@ -403,6 +327,7 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
private fun deleteButtonClick() {
activity?.hideKeyboard()
dialogBuilder
.newDialog(R.string.DLG_delete_this_task_question)
.setPositiveButton(R.string.ok) { _, _ -> delete() }
@ -435,6 +360,38 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
}
}
@Composable
private fun TitleRow(
requestFocus: Boolean,
) {
val isComplete = editViewModel.completed.collectAsStateWithLifecycle().value
val recurrence = editViewModel.recurrence.collectAsStateWithLifecycle().value
val isRecurring = remember(recurrence) {
!recurrence.isNullOrBlank()
}
org.tasks.compose.edit.TitleRow(
text = editViewModel.title,
onChanged = { text -> editViewModel.title = text.toString().trim { it <= ' ' } },
linkify = if (preferences.linkify) linkify else null,
markdownProvider = markdownProvider,
desaturate = remember { preferences.desaturateDarkMode },
isCompleted = isComplete,
isRecurring = isRecurring,
priority = editViewModel.priority.collectAsStateWithLifecycle().value,
onComplete = {
if (isComplete) {
editViewModel.completed.value = false
} else {
editViewModel.completed.value = true
lifecycleScope.launch {
save()
}
}
},
requestFocus = requestFocus,
)
}
@Composable
private fun DueDateRow() {
val dueDate = editViewModel.dueDate.collectAsStateWithLifecycle().value

@ -25,7 +25,6 @@ import org.tasks.data.entity.TaskAttachment
import org.tasks.dialogs.AddAttachmentDialog
import org.tasks.files.FileHelper
import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import org.tasks.ui.TaskEditControlFragment
import javax.inject.Inject
@ -48,7 +47,6 @@ class FilesControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
AttachmentRow(
attachments = viewModel.selectedAttachments.collectAsStateWithLifecycle().value,
openAttachment = {
@ -65,7 +63,6 @@ class FilesControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -26,7 +26,6 @@ import org.tasks.filters.GtasksFilter
import org.tasks.repeats.BasicRecurrenceDialog
import org.tasks.repeats.RecurrenceUtils.newRecur
import org.tasks.repeats.RepeatRuleToString
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.startOfDay
@ -86,7 +85,6 @@ class RepeatControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
RepeatRow(
recurrence = viewModel.recurrence.collectAsStateWithLifecycle().value?.let {
repeatRuleToString.toString(it)
@ -119,7 +117,6 @@ class RepeatControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -29,7 +29,6 @@ class TagsControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
TagsRow(
tags = viewModel.selectedTags.collectAsStateWithLifecycle().value,
colorProvider = { chipProvider.getColor(it) },
@ -40,7 +39,6 @@ class TagsControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -23,7 +23,6 @@ import org.tasks.data.entity.Task
import org.tasks.dialogs.DialogBuilder
import org.tasks.extensions.Context.is24HourFormat
import org.tasks.kmp.org.tasks.time.getTimeString
import org.tasks.themes.TasksTheme
import org.tasks.themes.Theme
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.ui.TaskEditControlFragment
@ -90,7 +89,6 @@ class TimerControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
TimerRow(
started = viewModel.timerStarted.collectAsStateWithLifecycle().value,
estimated = viewModel.estimatedSeconds.collectAsStateWithLifecycle().value,
@ -100,7 +98,6 @@ class TimerControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -31,7 +31,6 @@ import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.MyTimePickerDialog
import org.tasks.extensions.Context.openReminderSettings
import org.tasks.scheduling.NotificationSchedulerIntentService
import org.tasks.themes.TasksTheme
import org.tasks.ui.TaskEditControlFragment
import javax.inject.Inject
@ -76,7 +75,6 @@ class ReminderControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
val ringMode by remember { this@ReminderControlSet.ringMode }
val hasReminderPermissions by rememberReminderPermissionState()
val notificationPermissions = if (AndroidUtilities.atLeastTiramisu()) {
@ -128,7 +126,6 @@ class ReminderControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -23,7 +23,6 @@ import org.tasks.kmp.org.tasks.time.DateStyle
import org.tasks.kmp.org.tasks.time.getRelativeDateTime
import org.tasks.kmp.org.tasks.time.getTimeString
import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.withMillisOfDay
import org.tasks.ui.TaskEditControlFragment
@ -49,7 +48,6 @@ class StartDateControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?) =
(parent as ComposeView).apply {
setContent {
TasksTheme {
val selectedDay = vm.selectedDay.collectAsStateWithLifecycle().value
val selectedTime = vm.selectedTime.collectAsStateWithLifecycle().value
StartDateRow(
@ -86,7 +84,6 @@ class StartDateControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -17,13 +17,32 @@ fun CheckBox(
onCompleteClick: () -> Unit,
modifier: Modifier = Modifier,
desaturate: Boolean,
) {
CheckBox(
isCompleted = task.isCompleted,
isRecurring = task.isRecurring,
priority = task.priority,
onCompleteClick = onCompleteClick,
modifier = modifier,
desaturate = desaturate,
)
}
@Composable
fun CheckBox(
isCompleted: Boolean,
isRecurring: Boolean,
priority: Int,
onCompleteClick: () -> Unit,
modifier: Modifier = Modifier,
desaturate: Boolean,
) {
IconButton(onClick = onCompleteClick, modifier = modifier) {
Icon(
painter = painterResource(id = task.getCheckboxRes()),
painter = painterResource(id = getCheckboxRes(isCompleted, isRecurring)),
tint = Color(
priorityColor(
priority = task.priority,
priority = priority,
isDarkMode = isSystemInDarkTheme(),
desaturate = desaturate,
)

@ -1,6 +1,8 @@
package org.tasks.compose
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.ContentAlpha
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
@ -8,13 +10,17 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
@Composable
fun TaskEditIcon(@DrawableRes id: Int, modifier: Modifier = Modifier) {
Icon(
painter = painterResource(id = id),
contentDescription = null,
modifier = modifier.alpha(ContentAlpha.medium),
modifier = modifier
.alpha(ContentAlpha.medium)
.padding(12.dp)
.size(24.dp),
tint = MaterialTheme.colorScheme.onSurface,
)
}

@ -1,10 +1,12 @@
package org.tasks.compose
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.ContentAlpha
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
@ -19,10 +21,10 @@ fun TaskEditRow(
modifier = Modifier
.alpha(ContentAlpha.medium)
.padding(
start = 16.dp,
top = 20.dp,
end = 32.dp,
bottom = 20.dp
start = 4.dp,
top = 8.dp,
end = 20.dp,
bottom = 8.dp
)
)
},
@ -35,6 +37,7 @@ fun TaskEditRow(
enabled = onClick != null,
onClick = { onClick?.invoke() }
)
.background(MaterialTheme.colorScheme.surface),
) {
icon()
content()

@ -1,20 +1,16 @@
package org.tasks.compose.edit
import android.content.res.Configuration
import android.text.InputType
import android.util.TypedValue
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.widget.addTextChangedListener
import com.todoroo.andlib.utility.AndroidUtilities
import org.tasks.R
import org.tasks.compose.TaskEditRow
import org.tasks.dialogs.Linkify
@ -33,46 +29,12 @@ fun DescriptionRow(
content = {
Column(verticalArrangement = Arrangement.Center) {
Spacer(modifier = Modifier.height(11.dp))
AndroidView(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(end = 16.dp),
factory = { context ->
EditText(context).apply {
setText(text)
val textWatcher =
markdownProvider?.markdown(linkify != null)?.textWatcher(this)
addTextChangedListener(
onTextChanged = { text, _, _, _ -> onChanged(text) },
afterTextChanged = { editable -> textWatcher?.invoke(editable) }
)
setBackgroundColor(context.getColor(android.R.color.transparent))
textAlignment = View.TEXT_ALIGNMENT_VIEW_START
imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
inputType =
InputType.TYPE_CLASS_TEXT or
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or
InputType.TYPE_TEXT_FLAG_MULTI_LINE or
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
isSingleLine = false
maxLines = Int.MAX_VALUE
if (AndroidUtilities.atLeastOreo()) {
importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO
}
isVerticalScrollBarEnabled = true
freezesText = true
setHorizontallyScrolling(false)
isHorizontalScrollBarEnabled = false
setHint(R.string.TEA_note_label)
setHintTextColor(context.getColor(R.color.text_tertiary))
setTextSize(
TypedValue.COMPLEX_UNIT_PX,
context.resources.getDimension(R.dimen.task_edit_text_size)
)
linkify?.linkify(this)
}
},
EditTextView(
text = text,
hint = stringResource(R.string.TEA_note_label),
onChanged = onChanged,
linkify = linkify,
markdownProvider = markdownProvider,
)
Spacer(modifier = Modifier.height(11.dp))
}

@ -0,0 +1,106 @@
package org.tasks.compose.edit
import android.content.Context.INPUT_METHOD_SERVICE
import android.graphics.Paint
import android.text.InputType
import android.util.TypedValue
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.widget.addTextChangedListener
import com.todoroo.andlib.utility.AndroidUtilities
import org.tasks.R
import org.tasks.dialogs.Linkify
import org.tasks.markdown.MarkdownProvider
@Composable
fun EditTextView(
text: String?,
hint: String?,
onChanged: (CharSequence?) -> Unit,
linkify: Linkify?,
markdownProvider: MarkdownProvider?,
strikethrough: Boolean = false,
requestFocus: Boolean = false,
) {
val context = LocalContext.current
var shouldRequestFocus by remember { mutableStateOf(false) }
val focusRequester = remember { FocusRequester() }
AndroidView(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(end = 16.dp)
.focusRequester(focusRequester),
factory = { context ->
EditText(context).apply {
setText(text)
val textWatcher =
markdownProvider?.markdown(linkify != null)?.textWatcher(this)
addTextChangedListener(
onTextChanged = { text, _, _, _ -> onChanged(text) },
afterTextChanged = { editable -> textWatcher?.invoke(editable) }
)
setBackgroundColor(context.getColor(android.R.color.transparent))
textAlignment = View.TEXT_ALIGNMENT_VIEW_START
imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
inputType =
InputType.TYPE_CLASS_TEXT or
InputType.TYPE_TEXT_FLAG_CAP_SENTENCES or
InputType.TYPE_TEXT_FLAG_MULTI_LINE or
InputType.TYPE_TEXT_FLAG_AUTO_CORRECT
isSingleLine = false
maxLines = Int.MAX_VALUE
if (AndroidUtilities.atLeastOreo()) {
importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_NO
}
isVerticalScrollBarEnabled = true
freezesText = true
setHorizontallyScrolling(false)
isHorizontalScrollBarEnabled = false
setHint(hint)
setHintTextColor(context.getColor(R.color.text_tertiary))
setTextSize(
TypedValue.COMPLEX_UNIT_PX,
context.resources.getDimension(R.dimen.task_edit_text_size)
)
linkify?.linkify(this)
}
},
update = { view ->
if (shouldRequestFocus) {
view.requestFocus()
val imm = context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT)
shouldRequestFocus = false
}
view.paintFlags = if (strikethrough) {
view.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
} else {
view.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv()
}
},
)
LaunchedEffect(Unit) {
if (requestFocus) {
shouldRequestFocus = true
}
}
}

@ -70,10 +70,10 @@ fun SubtaskRow(
id = org.tasks.R.drawable.ic_subdirectory_arrow_right_black_24dp,
modifier = Modifier
.padding(
start = 16.dp,
top = 20.dp,
end = 20.dp,
bottom = 20.dp
start = 4.dp,
top = 8.dp,
end = 8.dp,
bottom = 8.dp
)
.alpha(ContentAlpha.medium),
)

@ -0,0 +1,111 @@
package org.tasks.compose.edit
import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.tasks.R
import org.tasks.compose.CheckBox
import org.tasks.compose.TaskEditRow
import org.tasks.dialogs.Linkify
import org.tasks.markdown.MarkdownProvider
import org.tasks.themes.TasksTheme
@Composable
fun TitleRow(
text: String?,
onChanged: (CharSequence?) -> Unit,
linkify: Linkify?,
markdownProvider: MarkdownProvider?,
desaturate: Boolean,
isCompleted: Boolean,
isRecurring: Boolean,
priority: Int,
onComplete: () -> Unit,
requestFocus: Boolean,
) {
TaskEditRow(
icon = {
CheckBox(
isCompleted = isCompleted,
isRecurring = isRecurring,
priority = priority,
onCompleteClick = onComplete,
desaturate = desaturate,
modifier = Modifier.padding(
start = 4.dp,
end = 20.dp,
)
)
},
content = {
Column(verticalArrangement = Arrangement.Center) {
Spacer(modifier = Modifier.height(3.dp))
EditTextView(
text = text,
hint = stringResource(R.string.TEA_title_hint),
onChanged = onChanged,
linkify = linkify,
markdownProvider = markdownProvider,
strikethrough = isCompleted,
requestFocus = requestFocus,
)
Spacer(modifier = Modifier.height(11.dp))
}
},
)
}
@ExperimentalComposeUiApi
@Preview(showBackground = true, widthDp = 320)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 320)
@Composable
fun EmptyTitlePreview() {
TasksTheme {
TitleRow(
text = null,
onChanged = {},
linkify = null,
markdownProvider = null,
desaturate = true,
isCompleted = false,
isRecurring = false,
priority = 0,
onComplete = {},
requestFocus = false,
)
}
}
@ExperimentalComposeUiApi
@Preview(showBackground = true, widthDp = 320)
@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, widthDp = 320)
@Composable
fun TitlePreview() {
TasksTheme {
TitleRow(
text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Eleifend quam adipiscing vitae proin sagittis. Faucibus a pellentesque sit amet porttitor eget dolor.
""".trimIndent(),
onChanged = {},
linkify = null,
markdownProvider = null,
desaturate = true,
isCompleted = false,
isRecurring = false,
priority = 0,
onComplete = {},
requestFocus = false,
)
}
}

@ -18,7 +18,6 @@ import org.tasks.calendars.CalendarProvider
import org.tasks.compose.edit.CalendarRow
import org.tasks.extensions.Context.toast
import org.tasks.preferences.PermissionChecker
import org.tasks.themes.TasksTheme
import timber.log.Timber
import javax.inject.Inject
@ -45,7 +44,6 @@ class CalendarControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
CalendarRow(
eventUri = viewModel.eventUri.collectAsStateWithLifecycle().value,
selectedCalendar = viewModel.selectedCalendar.collectAsStateWithLifecycle().value?.let {
@ -74,7 +72,6 @@ class CalendarControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -4,9 +4,9 @@ import android.content.Context
import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import org.tasks.data.entity.Task
import dagger.hilt.android.qualifiers.ActivityContext
import org.tasks.R
import org.tasks.data.entity.Task
import org.tasks.themes.ColorProvider
import javax.inject.Inject
@ -24,7 +24,9 @@ class CheckBoxProvider @Inject constructor(
}
companion object {
fun Task.getCheckboxRes() = when {
fun Task.getCheckboxRes() = getCheckboxRes(isCompleted, isRecurring)
fun getCheckboxRes(isCompleted: Boolean, isRecurring: Boolean) = when {
isCompleted -> R.drawable.ic_outline_check_box_24px
isRecurring -> R.drawable.ic_outline_repeat_24px
else -> R.drawable.ic_outline_check_box_outline_blank_24px

@ -29,7 +29,6 @@ import org.tasks.location.LocationPickerActivity
import org.tasks.preferences.PermissionChecker
import org.tasks.preferences.PermissionChecker.backgroundPermissions
import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import javax.inject.Inject
@AndroidEntryPoint
@ -85,7 +84,6 @@ class LocationControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply {
setContent {
TasksTheme {
val hasPermissions =
rememberMultiplePermissionsState(permissions = backgroundPermissions())
.allPermissionsGranted
@ -107,7 +105,6 @@ class LocationControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -25,7 +25,6 @@ import org.tasks.preferences.Preferences
import org.tasks.tasklist.SectionedDataSource
import org.tasks.tasklist.TasksResults
import org.tasks.themes.ColorProvider
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTimeUtils2.currentTimeMillis
import javax.inject.Inject
@ -55,7 +54,6 @@ class SubtaskControlSet : TaskEditControlFragment() {
(parent as ComposeView).apply {
listViewModel = ViewModelProvider(requireParentFragment())[TaskListViewModel::class.java]
setContent {
TasksTheme {
SubtaskRow(
originalFilter = viewModel.originalList,
filter = viewModel.selectedList.collectAsStateWithLifecycle().value,
@ -89,7 +87,6 @@ class SubtaskControlSet : TaskEditControlFragment() {
)
}
}
}
override fun controlId() = TAG

@ -102,11 +102,12 @@ class TaskEditViewModel @Inject constructor(
val isNew = task.isNew
var showBeastModeHint = MutableStateFlow(!preferences.shownBeastModeHint)
var creationDate: Long = task.creationDate
var modificationDate: Long = task.modificationDate
var completionDate: Long = task.completionDate
var title: String? = task.title
var completed: Boolean = task.isCompleted
var completed = MutableStateFlow(task.isCompleted)
var priority = MutableStateFlow(task.priority)
var description: String? = task.notes.stripCarriageReturns()
val recurrence = MutableStateFlow(task.recurrence)
@ -217,7 +218,7 @@ class TaskEditViewModel @Inject constructor(
fun hasChanges(): Boolean =
(task.title != title || (isNew && title?.isNotBlank() == true)) ||
task.isCompleted != completed ||
task.isCompleted != completed.value ||
task.dueDate != dueDate.value ||
task.priority != priority.value ||
if (task.notes.isNullOrBlank()) {
@ -399,10 +400,10 @@ class TaskEditViewModel @Inject constructor(
.let { taskAttachmentDao.insert(it) }
}
if (task.isCompleted != completed) {
taskCompleter.setComplete(task, completed)
if (task.isCompleted != completed.value) {
taskCompleter.setComplete(task, completed.value)
if (task.isCompleted) {
firebase?.completeTask("edit_screen")
firebase?.completeTask("edit_screen_v2")
}
}
@ -503,6 +504,12 @@ class TaskEditViewModel @Inject constructor(
}
}
fun hideBeastModeHint(click: Boolean) {
showBeastModeHint.value = false
preferences.shownBeastModeHint = true
firebase?.logEvent(R.string.event_banner_beast, R.string.param_click to click)
}
init {
viewModelScope.launch {
taskAttachmentDao.getAttachments(task.id).let { attachments ->

@ -1,108 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingtoolbarlayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/content_background"
app:collapsedTitleTextAppearance="?attr/textAppearanceHeadline6"
app:expandedTitleGravity="top"
app:expandedTitleMarginTop="?attr/actionBarSize"
app:expandedTitleMarginStart="@dimen/keyline_first"
app:expandedTitleTextAppearance="?attr/textAppearanceHeadline5"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<EditText
android:id="@+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingTop="?attr/actionBarSize"
android:paddingStart="@dimen/keyline_first"
android:paddingEnd="@dimen/keyline_first"
android:paddingBottom="@dimen/keyline_second"
android:layout_gravity="top"
android:background="@null"
android:gravity="start"
android:textAppearance="?attr/textAppearanceHeadline5"
android:hint="@string/TEA_title_hint"
android:imeOptions="flagNoExtractUi"
android:importantForAutofill="no"
android:inputType="textCapSentences|textAutoCorrect"
android:scrollbars="vertical"
android:textAlignment="viewStart" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:elevation="@dimen/elevation_toolbar"
android:theme="@style/ToolbarTheme"
app:layout_collapseMode="pin"
app:navigationIconTint="@color/text_primary"
app:toolbarStyle="@style/Widget.MaterialComponents.Toolbar"
app:popupTheme="@style/popup_overlay"
tools:ignore="UnusedAttribute" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.core.widget.NestedScrollView
android:scrollbarStyle="outsideOverlay"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="100"
android:elevation="0dp"
android:overScrollMode="never">
<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.core.widget.NestedScrollView>
<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>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/keyline_first"
android:src="@drawable/ic_outline_check_box_24px"
android:soundEffectsEnabled="false"
app:layout_anchor="@id/appbarlayout"
app:layout_anchorGravity="bottom|end" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -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_comment_bar"
android:name="org.tasks.fragments.CommentBarFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_discard"
android:icon="@drawable/ic_outline_clear_24px"
android:title="@string/menu_discard_changes"
app:showAsAction="never" />
<item
android:id="@+id/menu_delete"
android:icon="@drawable/ic_outline_delete_24px"
android:title="@string/delete_task"
app:showAsAction="never"/>
</menu>

@ -609,7 +609,6 @@
<string name="custom_filter_criteria">معايير التصفية</string>
<string name="settings_default">افتراضي</string>
<string name="widget_id">معرف ويدجت: %d</string>
<string name="hide_check_button">إخفاء مربع الاختيار</string>
<string name="calendar_event_created">تم إنشاء حدث التقويم ل%s</string>
<string name="auto_dismiss_datetime_summary">إغلاق منتقي التاريخ والوقت بعد تحديد التاريخ أو الوقت</string>
<string name="auto_dismiss_datetime_widget_summary">الغلق التلقائي عند الانتقاء من ويدجت</string>

@ -593,7 +593,6 @@
<string name="desaturate_colors_summary_on">При тъмите теми цветовете ще бъдат с намалена наситеност</string>
<string name="sort_created_group">Създадена %s</string>
<string name="desaturate_colors_summary_off">При тъмите теми цветовете няма да бъдат променяни</string>
<string name="hide_check_button">Скриване на бутона за отмятане</string>
<string name="sort_modified_group">Променена %s</string>
<string name="github_sponsor">Дарител</string>
<string name="tasks_org_account_required">Необходим е профил в Tasks.org</string>

@ -515,7 +515,6 @@
<string name="custom_filter_criteria">Podmínky filtru</string>
<string name="compact">Kompaktní</string>
<string name="settings_default">Výchozí</string>
<string name="hide_check_button">Skrýt zaškrtávací políčko</string>
<string name="share">Sdílet</string>
<string name="select_all">Vybrat vše</string>
<string name="calendar_event_created">Událost v kalendáři vytvořena pro %s</string>

@ -115,7 +115,6 @@
<string name="compact">Kompakt</string>
<string name="settings_default">Standard</string>
<string name="widget_id">Widget-ID: %d</string>
<string name="hide_check_button">Skjul afkrydsningsknap</string>
<string name="share">Del</string>
<string name="select_all">Vælg alle</string>
<string name="calendar_event_created">Kalenderbegivenhed oprettet for %s</string>

@ -461,7 +461,6 @@
<string name="calendar_event_created">Kalendereintrag für %s erstellt</string>
<string name="select_all">Alles auswählen</string>
<string name="share">Teilen</string>
<string name="hide_check_button">Erledigt-Schaltfläche ausblenden</string>
<string name="widget_show_dividers">Trennlinien anzeigen</string>
<string name="opacity_footer">Deckkraft der Fußzeile</string>
<string name="opacity_row">Deckkraft der Zeilen</string>

@ -604,7 +604,6 @@
<string name="invalid_backup_file">Nevalida savkopio</string>
<string name="davx5_selection_description">Sinkronigi viajn taskojn kun la DAVx⁵ programeto</string>
<string name="navigation_drawer">Naviga tirkesto</string>
<string name="hide_check_button">Kaŝi elektobutonon</string>
<string name="filter_any_due_date">Ajna limdato</string>
<string name="filter_high_priority">Grava</string>
<string name="filter_medium_priority">Meza prioritato</string>

@ -475,7 +475,6 @@
<string name="calendar_event_created">Calendario de eventos creado para %s</string>
<string name="share">Compartir</string>
<string name="select_all">Seleccionar todo</string>
<string name="hide_check_button">Ocultar botón de verificación</string>
<string name="compact">Compacto</string>
<string name="settings_default">Predefinido</string>
<string name="widget_id">Widget ID: %d</string>

@ -456,7 +456,6 @@
<string name="no_date">Datarik ez</string>
<string name="auto_dismiss_datetime_summary">Itxi data/ordu hautatzailea behin data eta ordua hautatuta</string>
<string name="auto_dismiss_datetime">Automatikoki itxi data/ordu hautatzailea</string>
<string name="hide_check_button">Ezkutatu egiaztaketa botoia</string>
<string name="share">Partekatu</string>
<string name="select_all">Hautatu denak</string>
<string name="calendar_event_created">%s gertaera sortu da egutegian</string>

@ -437,7 +437,6 @@
<string name="add_tags">Lisää tunniste</string>
<string name="filter_any_due_date">Mikä tahansa määräpäivä</string>
<string name="settings_default">Oletusarvo</string>
<string name="hide_check_button">Piilota valinta painike</string>
<string name="share">Jaa</string>
<string name="select_all">Valitse kaikki</string>
<string name="widget_show_menu">Näytä valikko</string>

@ -475,7 +475,6 @@
<string name="calendar_event_created">Évènement de calendrier créé pour %s</string>
<string name="share">Partager</string>
<string name="select_all">Tout sélectionner</string>
<string name="hide_check_button">Masquer le bouton de vérification</string>
<string name="compact">Compacte</string>
<string name="settings_default">Par défaut</string>
<string name="widget_id">Identifiant du widget: %d</string>

@ -376,7 +376,6 @@
<item quantity="one">minuto</item>
<item quantity="other">minutos</item>
</plurals>
<string name="hide_check_button">Agochar botón de marcar</string>
<string name="settings_default">Predefinido</string>
<string name="price_per_year">$%s/ano</string>
<string name="migrate_count">Mover %s a Tasks.org</string>

@ -535,7 +535,6 @@
<string name="compact">Kompaktno</string>
<string name="settings_default">Standardno</string>
<string name="widget_id">Widget ID: %d</string>
<string name="hide_check_button">Sakrij potvrdni gumb</string>
<string name="share">Dijeli</string>
<string name="select_all">Odaberi sve</string>
<string name="calendar_event_created">Kalendarski događaj stvoren za %s</string>

@ -454,7 +454,6 @@
<string name="calendar_event_created">Naptár esemény létrehozva: %s</string>
<string name="share">Megosztás</string>
<string name="select_all">Az összes kiválasztása</string>
<string name="hide_check_button">PIpa gomb elrejtése</string>
<string name="compact">Kompakt</string>
<string name="settings_default">Alapértelmezett</string>
<string name="widget_id">Widget azonosító: %d</string>

@ -355,7 +355,6 @@
<string name="more_notification_settings_summary">Nada dering, getar, dan lainnya</string>
<string name="actfm_picture_clear">Hapus Gambar</string>
<string name="settings_default">Bawaan</string>
<string name="hide_check_button">Sembunyikan tombol centang</string>
<string name="share">Bagikan</string>
<string name="select_all">Pilih Semua</string>
<string name="calendar_event_created">Acara kalender dibuat untuk %s</string>

@ -501,7 +501,6 @@
<string name="compact">Compatto</string>
<string name="settings_default">Predefinito</string>
<string name="widget_id">ID widget: %d</string>
<string name="hide_check_button">Nascondi casella di selezione</string>
<string name="opacity_footer">Opacità piè di pagina</string>
<string name="opacity_row">Opacità riga</string>
<string name="opacity_header">Opacità intestazione</string>

@ -472,7 +472,6 @@
<string name="compact">קומפקטי</string>
<string name="settings_default">בררת מחדל</string>
<string name="widget_id">מזהה וידג׳ט: %d</string>
<string name="hide_check_button">הסתרת כפתור הסימון</string>
<string name="share">שיתוף</string>
<string name="auto_dismiss_datetime_widget">יישומון</string>
<string name="shortcut_pick_time">בחירת זמן</string>

@ -524,7 +524,6 @@
<string name="auto_dismiss_datetime_list_summary">タスクリストから選択時に自動で閉じる</string>
<string name="auto_dismiss_datetime_widget_summary">ウィジェットから選択時に自動で閉じる</string>
<string name="auto_dismiss_datetime_summary">日付または時刻を選択したあとに日時選択画面を閉じる</string>
<string name="hide_check_button">チェックボタンを非表示</string>
<string name="widget_id">ウィジェット ID: %d</string>
<string name="filter_overdue">遅延</string>
<string name="filter_any_due_date">締切あり</string>

@ -478,7 +478,6 @@
<string name="custom_filter_and">그리고</string>
<string name="custom_filter_criteria">필터 조건</string>
<string name="widget_id">위젯 ID: %d</string>
<string name="hide_check_button">체크 버튼 숨기기</string>
<string name="auto_dismiss_datetime_summary">날짜나 시간을 선택한 후에 일시 선택상자 닫기</string>
<string name="auto_dismiss_datetime_widget_summary">위젯에서 선택시 닫기</string>
<string name="auto_dismiss_datetime_widget">위젯</string>

@ -530,7 +530,6 @@
<string name="display_name">Rodomas pavadinimas</string>
<string name="date_picker_multiple">Keleta</string>
<string name="compact">Kompaktiška</string>
<string name="hide_check_button">Slėpti žymėjimo mygtuką</string>
<string name="navigation_drawer">Navigacijos parankinės juosta</string>
<string name="foreground_location">Vietos nustatymas</string>
<string name="background_location">Foninis vietos nustatymas</string>

@ -461,7 +461,6 @@
<string name="widget_show_dividers">Vis inndelere</string>
<string name="filter_overdue">Forsinket</string>
<string name="custom_filter_criteria">Filterkriterium</string>
<string name="hide_check_button">Skjul bekreftelsesknapp</string>
<string name="calendar_event_created">Kalenderhendelse opprettet for %s</string>
<string name="auto_dismiss_datetime_summary">Lukk datovelger etter å ha valgt dato eller tid</string>
<string name="auto_dismiss_datetime_widget_summary">Lukk automatisk når valgt fra miniprogram</string>

@ -454,7 +454,6 @@
<string name="calendar_event_created">Kalender-item aangemaakt voor %s</string>
<string name="share">Taken delen</string>
<string name="select_all">Alles selecteren</string>
<string name="hide_check_button">Selectievakje verbergen</string>
<string name="compact">Compact</string>
<string name="settings_default">Standaardwaarde</string>
<string name="widget_id">Widget ID: %d</string>

@ -468,7 +468,6 @@
<string name="compact">Kompaktowy</string>
<string name="settings_default">Domyślny</string>
<string name="widget_id">Identyfikator widżetu: %d</string>
<string name="hide_check_button">Ukryj przycisk wyboru</string>
<string name="share">Udostępnij</string>
<string name="select_all">Zaznacz wszystko</string>
<string name="calendar_event_created">Wydarzenie kalendarzowe utworzone dla %s</string>

@ -396,7 +396,6 @@
<string name="open_map">Abrir mapa</string>
<string name="choose_new_location">Escolher nova localização</string>
<string name="widget_id">ID do widget: %d</string>
<string name="hide_check_button">Ocultar botão de verificação</string>
<string name="share">Compartilhar</string>
<string name="select_all">Selecionar todos</string>
<string name="calendar_event_created">Evento de calendário criado para %s</string>

@ -436,7 +436,6 @@
<string name="settings_default">Predefinição</string>
<string name="widget_show_menu">Mostrar menu</string>
<string name="widget_id">ID do widget: %d</string>
<string name="hide_check_button">Ocultar botão de verificado</string>
<string name="share">Partilhar</string>
<string name="select_all">Selecionar todos</string>
<string name="calendar_event_created">Evento de calendário criado para %s</string>

@ -534,7 +534,6 @@
<string name="custom_filter_criteria">Criterii de filtrare</string>
<string name="settings_default">Implicit</string>
<string name="widget_id">ID-ul aplicației: %d</string>
<string name="hide_check_button">Ascunde butonul de verificare</string>
<string name="share">Distribuie</string>
<string name="select_all">Selectează toate</string>
<string name="calendar_event_created">Eveniment calendaristic creat pentru %s</string>

@ -471,7 +471,6 @@
<string name="place_settings">Настройки места</string>
<string name="places">Места</string>
<string name="menu_discard_changes">Отменить изменения</string>
<string name="hide_check_button">Скрыть кнопку для галочки</string>
<string name="share">Поделиться</string>
<string name="select_all">Выбрать всё</string>
<string name="calendar_event_created">В календаре создано событие для %s</string>

@ -151,7 +151,6 @@
<string name="custom_filter_and">සහ</string>
<string name="custom_filter_criteria">පෙරහන් නිර්ණායක</string>
<string name="settings_default">පෙරනිමිය</string>
<string name="hide_check_button">පිරික්සුම් බොත්තම සඟවන්න</string>
<string name="share">බෙදාගන්න</string>
<string name="select_all">සියල්ල තෝරන්න</string>
<string name="auto_dismiss_datetime_summary">දිනයක් හෝ වේලාවක් තේරීමෙන් පසු දිනය, වේලාව තෝරනය වසා දමන්න</string>

@ -548,7 +548,6 @@
<string name="filter_overdue">Försenad</string>
<string name="custom_filter_criteria">Filterkriterier</string>
<string name="widget_id">Widget-ID: %d</string>
<string name="hide_check_button">Dölj kontrollknappen</string>
<string name="calendar_event_created">Kalenderhändelse skapad för %s</string>
<string name="auto_dismiss_datetime_summary">Stänga datum- och tidsväljare efter att ha valt ett datum eller en tid</string>
<string name="auto_dismiss_datetime_widget_summary">Stäng automatiskt vid val från uppgiftslistan</string>

@ -161,7 +161,6 @@
<string name="compact">கச்சிதமான</string>
<string name="settings_default">இயல்புநிலை</string>
<string name="widget_id">விட்ஜெட் ஐடி: %d</string>
<string name="hide_check_button">சோதனை பொத்தானை மறைக்க</string>
<string name="share">பகிர்</string>
<string name="select_all">அனைத்தையும் தெரிவுசெய்</string>
<string name="calendar_event_created">%s க்கு காலண்டர் நிகழ்வு உருவாக்கப்பட்டது</string>

@ -536,7 +536,6 @@
<string name="compact">ข้อตกลง</string>
<string name="settings_default">ค่าเริ่มต้น</string>
<string name="widget_id">รหัสวิดเจ็ต: %d</string>
<string name="hide_check_button">ซ่อนปุ่มตรวจสอบ</string>
<string name="share">ใช้ร่วมกัน</string>
<string name="select_all">เลือกทั้งหมด</string>
<string name="calendar_event_created">เหตุการณ์ในปฏิทินที่สร้างสําหรับ %s</string>

@ -457,7 +457,6 @@
<string name="chip_appearance_text_only">Yalnızca metin</string>
<string name="chip_appearance_text_and_icon">Metin ve simge</string>
<string name="menu_discard_changes">Değişiklikleri göz ardı et</string>
<string name="hide_check_button">Denetim düğmesini gizle</string>
<string name="share">Paylaş</string>
<string name="select_all">Tümünü seç</string>
<string name="compact">Sıkı</string>

@ -477,7 +477,6 @@
<string name="disable_battery_optimizations">Вимкнути оптимізацію енергоспоживання</string>
<string name="notification_troubleshooting_summary">Натисніть тут, якщо маєте проблеми з повідомленнями</string>
<string name="troubleshooting">Розв\'язання проблем</string>
<string name="hide_check_button">Сховати кнопку для галочки</string>
<string name="sort_created">За часом створення</string>
<string name="copied_to_clipboard">%s скопійовано в буфер обміну</string>
<string name="app_password_save">Використовуйте ці дані для налаштування стороннього застосунку. Вони надають повний доступ до вашого облікового запису Tasks.org, не записуйте їх та нікому не повідомляйте!</string>

@ -175,7 +175,6 @@
<string name="compact">Nhỏ gọn</string>
<string name="settings_default">Mặc định</string>
<string name="widget_id">ID tiện ích: %d</string>
<string name="hide_check_button">Ẩn nút hoàn thành</string>
<string name="share">Chia sẻ</string>
<string name="select_all">Chọn tất cả</string>
<string name="calendar_event_created">Đã tạo sự kiện trong lịch cho %s</string>

@ -449,7 +449,6 @@
<string name="share">分享</string>
<string name="select_all">选中全部</string>
<string name="calendar_event_created">已为 %s 创建日历事件</string>
<string name="hide_check_button">隐藏检查按钮</string>
<string name="compact">紧凑</string>
<string name="settings_default">默认</string>
<string name="widget_id">部件ID%d</string>

@ -331,7 +331,6 @@
<string name="custom_filter_criteria">編輯器標準</string>
<string name="compact"></string>
<string name="settings_default">預設</string>
<string name="hide_check_button">隱藏勾選鈕</string>
<string name="share">分享</string>
<string name="select_all">選擇全部</string>
<string name="auto_dismiss_datetime_summary">選擇日期或時間後關閉日期時間選擇器</string>

@ -393,7 +393,6 @@
<string name="p_auto_dismiss_datetime_edit_screen">auto_dismiss_datetime_edit_screen</string>
<string name="p_auto_dismiss_datetime_list_screen">auto_dismiss_datetime_list_screen</string>
<string name="p_auto_dismiss_datetime_widget">auto_dismiss_datetime_widget</string>
<string name="p_hide_check_button">Hide check button</string>
<string name="p_show_whats_new">show_whats_new</string>
<string name="p_just_updated">just_updated</string>
<string name="p_last_review_request">last_review_request</string>

@ -581,7 +581,6 @@ File %1$s contained %2$s.\n\n
<string name="calendar_event_created">Calendar event created for %s</string>
<string name="select_all">Select all</string>
<string name="share">Share</string>
<string name="hide_check_button">Hide check button</string>
<string name="widget_id">Widget ID: %d</string>
<string name="settings_default">Default</string>
<string name="compact">Compact</string>

@ -24,11 +24,6 @@
android:key="@string/p_back_button_saves_task"
android:title="@string/back_button_saves_task" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="@string/p_hide_check_button"
android:title="@string/hide_check_button" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="@string/p_show_task_edit_comments"

Loading…
Cancel
Save