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 package com.todoroo.astrid.activity
import android.app.Activity import android.app.Activity
import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Paint
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import androidx.activity.compose.BackHandler
import android.view.inputmethod.InputMethodManager
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts 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.animation.ExperimentalAnimationApi
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Divider 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.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.remember
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.Modifier
import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.viewinterop.AndroidViewBinding import androidx.compose.ui.viewinterop.AndroidViewBinding
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.os.BundleCompat import androidx.core.os.BundleCompat
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope 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.andlib.utility.AndroidUtilities.atLeastOreoMR1
import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.files.FilesControlSet 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.Alarm
import org.tasks.data.entity.TagData import org.tasks.data.entity.TagData
import org.tasks.data.entity.Task import org.tasks.data.entity.Task
import org.tasks.databinding.FragmentTaskEditBinding
import org.tasks.databinding.TaskEditCalendarBinding import org.tasks.databinding.TaskEditCalendarBinding
import org.tasks.databinding.TaskEditCommentBarBinding
import org.tasks.databinding.TaskEditFilesBinding import org.tasks.databinding.TaskEditFilesBinding
import org.tasks.databinding.TaskEditLocationBinding import org.tasks.databinding.TaskEditLocationBinding
import org.tasks.databinding.TaskEditRemindersBinding import org.tasks.databinding.TaskEditRemindersBinding
@ -106,6 +102,7 @@ import org.tasks.notifications.NotificationManager
import org.tasks.play.PlayServices import org.tasks.play.PlayServices
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme import org.tasks.themes.TasksTheme
import org.tasks.themes.Theme
import org.tasks.ui.CalendarControlSet import org.tasks.ui.CalendarControlSet
import org.tasks.ui.ChipProvider import org.tasks.ui.ChipProvider
import org.tasks.ui.LocationControlSet import org.tasks.ui.LocationControlSet
@ -116,10 +113,9 @@ import org.tasks.ui.TaskEditViewModel
import org.tasks.ui.TaskEditViewModel.Companion.stripCarriageReturns import org.tasks.ui.TaskEditViewModel.Companion.stripCarriageReturns
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import kotlin.math.abs
@AndroidEntryPoint @AndroidEntryPoint
class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener { class TaskEditFragment : Fragment() {
@Inject lateinit var taskDao: TaskDao @Inject lateinit var taskDao: TaskDao
@Inject lateinit var userActivityDao: UserActivityDao @Inject lateinit var userActivityDao: UserActivityDao
@Inject lateinit var notificationManager: NotificationManager @Inject lateinit var notificationManager: NotificationManager
@ -134,9 +130,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
@Inject lateinit var locale: Locale @Inject lateinit var locale: Locale
@Inject lateinit var chipProvider: ChipProvider @Inject lateinit var chipProvider: ChipProvider
@Inject lateinit var playServices: PlayServices @Inject lateinit var playServices: PlayServices
@Inject lateinit var theme: Theme
val editViewModel: TaskEditViewModel by viewModels() private val editViewModel: TaskEditViewModel by viewModels()
lateinit var binding: FragmentTaskEditBinding
private var showKeyboard = false private var showKeyboard = false
private val beastMode = private val beastMode =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
@ -149,166 +145,141 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
val task: Task? val task: Task?
get() = BundleCompat.getParcelable(requireArguments(), EXTRA_TASK, Task::class.java) get() = BundleCompat.getParcelable(requireArguments(), EXTRA_TASK, Task::class.java)
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterial3Api::class)
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
requireActivity().onBackPressedDispatcher.addCallback(owner = viewLifecycleOwner) {
if (preferences.backButtonSavesTask()) {
lifecycleScope.launch {
save()
}
} else {
discardButtonClick()
}
}
if (atLeastOreoMR1()) { if (atLeastOreoMR1()) {
activity?.setShowWhenLocked(preferences.showEditScreenWithoutUnlock) activity?.setShowWhenLocked(preferences.showEditScreenWithoutUnlock)
} }
binding = FragmentTaskEditBinding.inflate(inflater)
val view: View = binding.root
val model = editViewModel.task val model = editViewModel.task
val toolbar = binding.toolbar if (!model.isNew) {
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 { 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) { if (savedInstanceState == null) {
showKeyboard = model.isNew && isNullOrEmpty(model.title) showKeyboard = model.isNew && isNullOrEmpty(model.title)
} }
val params = binding.appbarlayout.layoutParams as CoordinatorLayout.LayoutParams val backButtonSavesTask = preferences.backButtonSavesTask()
params.behavior = AppBarLayout.Behavior() val view = ComposeView(context).apply {
val behavior = params.behavior as AppBarLayout.Behavior? setContent {
behavior!!.setDragCallback(object : DragCallback() { BackHandler {
override fun canDrag(appBarLayout: AppBarLayout): Boolean { if (backButtonSavesTask) {
return false lifecycleScope.launch {
} save()
}) }
toolbar.setOnMenuItemClickListener(this) } else {
val title = binding.title discardButtonClick()
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()
} }
} TasksTheme(theme = theme.themeBase.index,) {
} Scaffold(
binding.appbarlayout.addOnOffsetChangedListener { appBarLayout, verticalOffset -> topBar = {
if (verticalOffset == 0) { TopAppBar(
title.visibility = View.VISIBLE navigationIcon = {
binding.collapsingtoolbarlayout.isTitleEnabled = false IconButton(
} else if (abs(verticalOffset) < appBarLayout.totalScrollRange) { onClick = {
title.visibility = View.INVISIBLE when {
binding.collapsingtoolbarlayout.title = title.text editViewModel.isReadOnly -> activity?.onBackPressed()
binding.collapsingtoolbarlayout.isTitleEnabled = true backButtonSavesTask -> discardButtonClick()
} else -> lifecycleScope.launch { save() }
} }
if (!model.isNew) { }
lifecycleScope.launch { ) {
notificationManager.cancel(model.id) Icon(
} imageVector = when {
if (preferences.linkify) { editViewModel.isReadOnly -> Icons.AutoMirrored.Outlined.ArrowBack
linkify.linkify(title) backButtonSavesTask -> Icons.Outlined.Clear
} else -> Icons.Outlined.Save
} },
binding.composeView.setContent { contentDescription = when {
TasksTheme { editViewModel.isReadOnly -> stringResource(R.string.back)
Column(modifier = Modifier.gesturesDisabled(editViewModel.isReadOnly)) { backButtonSavesTask -> stringResource(R.string.discard)
taskEditControlSetFragmentManager.displayOrder.forEachIndexed { index, tag -> else -> stringResource(R.string.save)
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() title = {},
TAG_DESCRIPTION -> DescriptionRow() actions = {
TAG_LIST -> ListRow() if (backButtonSavesTask && editViewModel.isWritable) {
TAG_CREATION -> CreationRow() IconButton(onClick = { discardButtonClick() }) {
CalendarControlSet.TAG -> AndroidViewBinding(TaskEditCalendarBinding::inflate) Icon(
StartDateControlSet.TAG -> AndroidViewBinding( imageVector = Icons.Outlined.Clear,
TaskEditStartDateBinding::inflate contentDescription = stringResource(R.string.menu_discard_changes),
) )
ReminderControlSet.TAG -> AndroidViewBinding( }
TaskEditRemindersBinding::inflate }
) if (!editViewModel.isNew && editViewModel.isWritable) {
LocationControlSet.TAG -> AndroidViewBinding(TaskEditLocationBinding::inflate) IconButton(onClick = { deleteButtonClick() }) {
FilesControlSet.TAG -> AndroidViewBinding(TaskEditFilesBinding::inflate) Icon(
TimerControlSet.TAG -> AndroidViewBinding(TaskEditTimerBinding::inflate) imageVector = Icons.Outlined.Delete,
TagsControlSet.TAG -> AndroidViewBinding(TaskEditTagsBinding::inflate) contentDescription = stringResource(R.string.delete_task),
RepeatControlSet.TAG -> AndroidViewBinding(TaskEditRepeatBinding::inflate) )
SubtaskControlSet.TAG -> AndroidViewBinding(TaskEditSubtasksBinding::inflate) }
else -> throw IllegalArgumentException("Unknown row: $tag") }
},
)
},
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
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")
}
HorizontalDivider()
}
}
if (preferences.getBoolean(R.string.p_show_task_edit_comments, false)) {
Comments()
} }
Divider(modifier = Modifier.fillMaxWidth()) 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)
}
)
} }
} }
if (preferences.getBoolean(R.string.p_show_task_edit_comments, false)) {
Comments()
}
} }
} }
} }
@ -337,61 +308,14 @@ 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) { suspend fun save(remove: Boolean = true) {
editViewModel.save(remove) editViewModel.save(remove)
activity?.let { playServices.requestReview(it) } activity?.let { playServices.requestReview(it) }
} }
private fun discardButtonClick() { private fun discardButtonClick() {
if (editViewModel.hasChanges()) { activity?.hideKeyboard()
if (editViewModel.hasChanges()) {
dialogBuilder dialogBuilder
.newDialog(R.string.discard_confirmation) .newDialog(R.string.discard_confirmation)
.setPositiveButton(R.string.keep_editing, null) .setPositiveButton(R.string.keep_editing, null)
@ -403,6 +327,7 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
} }
private fun deleteButtonClick() { private fun deleteButtonClick() {
activity?.hideKeyboard()
dialogBuilder dialogBuilder
.newDialog(R.string.DLG_delete_this_task_question) .newDialog(R.string.DLG_delete_this_task_question)
.setPositiveButton(R.string.ok) { _, _ -> delete() } .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 @Composable
private fun DueDateRow() { private fun DueDateRow() {
val dueDate = editViewModel.dueDate.collectAsStateWithLifecycle().value val dueDate = editViewModel.dueDate.collectAsStateWithLifecycle().value

@ -25,7 +25,6 @@ import org.tasks.data.entity.TaskAttachment
import org.tasks.dialogs.AddAttachmentDialog import org.tasks.dialogs.AddAttachmentDialog
import org.tasks.files.FileHelper import org.tasks.files.FileHelper
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import org.tasks.ui.TaskEditControlFragment import org.tasks.ui.TaskEditControlFragment
import javax.inject.Inject import javax.inject.Inject
@ -48,22 +47,20 @@ class FilesControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View = override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { AttachmentRow(
AttachmentRow( attachments = viewModel.selectedAttachments.collectAsStateWithLifecycle().value,
attachments = viewModel.selectedAttachments.collectAsStateWithLifecycle().value, openAttachment = {
openAttachment = { FileHelper.startActionView(
FileHelper.startActionView( requireActivity(),
requireActivity(), if (Strings.isNullOrEmpty(it.uri)) null else Uri.parse(it.uri)
if (Strings.isNullOrEmpty(it.uri)) null else Uri.parse(it.uri) )
) },
}, deleteAttachment = this@FilesControlSet::deleteAttachment,
deleteAttachment = this@FilesControlSet::deleteAttachment, addAttachment = {
addAttachment = { AddAttachmentDialog.newAddAttachmentDialog(this@FilesControlSet)
AddAttachmentDialog.newAddAttachmentDialog(this@FilesControlSet) .show(parentFragmentManager, FRAG_TAG_ADD_ATTACHMENT_DIALOG)
.show(parentFragmentManager, FRAG_TAG_ADD_ATTACHMENT_DIALOG) },
}, )
)
}
} }
} }

@ -26,7 +26,6 @@ import org.tasks.filters.GtasksFilter
import org.tasks.repeats.BasicRecurrenceDialog import org.tasks.repeats.BasicRecurrenceDialog
import org.tasks.repeats.RecurrenceUtils.newRecur import org.tasks.repeats.RecurrenceUtils.newRecur
import org.tasks.repeats.RepeatRuleToString import org.tasks.repeats.RepeatRuleToString
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTime import org.tasks.time.DateTime
import org.tasks.time.DateTimeUtils2.currentTimeMillis import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.startOfDay import org.tasks.time.startOfDay
@ -86,38 +85,36 @@ class RepeatControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View = override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { RepeatRow(
RepeatRow( recurrence = viewModel.recurrence.collectAsStateWithLifecycle().value?.let {
recurrence = viewModel.recurrence.collectAsStateWithLifecycle().value?.let { repeatRuleToString.toString(it)
repeatRuleToString.toString(it) },
}, repeatAfterCompletion = viewModel.repeatAfterCompletion.collectAsStateWithLifecycle().value,
repeatAfterCompletion = viewModel.repeatAfterCompletion.collectAsStateWithLifecycle().value, onClick = {
onClick = { lifecycleScope.launch {
lifecycleScope.launch { val accountType = viewModel.selectedList.value
val accountType = viewModel.selectedList.value .let {
.let { when (it) {
when (it) { is CaldavFilter -> it.account
is CaldavFilter -> it.account is GtasksFilter -> it.account
is GtasksFilter -> it.account else -> null
else -> null
}
} }
?.let { caldavDao.getAccountByUuid(it) } }
?.accountType ?.let { caldavDao.getAccountByUuid(it) }
?: CaldavAccount.TYPE_LOCAL ?.accountType
BasicRecurrenceDialog.newBasicRecurrenceDialog( ?: CaldavAccount.TYPE_LOCAL
target = this@RepeatControlSet, BasicRecurrenceDialog.newBasicRecurrenceDialog(
rc = REQUEST_RECURRENCE, target = this@RepeatControlSet,
rrule = viewModel.recurrence.value, rc = REQUEST_RECURRENCE,
dueDate = viewModel.dueDate.value, rrule = viewModel.recurrence.value,
accountType = accountType, dueDate = viewModel.dueDate.value,
) accountType = accountType,
.show(parentFragmentManager, FRAG_TAG_BASIC_RECURRENCE) )
} .show(parentFragmentManager, FRAG_TAG_BASIC_RECURRENCE)
}, }
onRepeatFromChanged = { viewModel.repeatAfterCompletion.value = it } },
) onRepeatFromChanged = { viewModel.repeatAfterCompletion.value = it }
} )
} }
} }

@ -29,16 +29,14 @@ class TagsControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View = override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { TagsRow(
TagsRow( tags = viewModel.selectedTags.collectAsStateWithLifecycle().value,
tags = viewModel.selectedTags.collectAsStateWithLifecycle().value, colorProvider = { chipProvider.getColor(it) },
colorProvider = { chipProvider.getColor(it) }, onClick = this@TagsControlSet::onRowClick,
onClick = this@TagsControlSet::onRowClick, onClear = { tag ->
onClear = { tag -> viewModel.selectedTags.update { ArrayList(it.minus(tag)) }
viewModel.selectedTags.update { ArrayList(it.minus(tag)) } },
}, )
)
}
} }
} }

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

@ -31,7 +31,6 @@ import org.tasks.dialogs.DialogBuilder
import org.tasks.dialogs.MyTimePickerDialog import org.tasks.dialogs.MyTimePickerDialog
import org.tasks.extensions.Context.openReminderSettings import org.tasks.extensions.Context.openReminderSettings
import org.tasks.scheduling.NotificationSchedulerIntentService import org.tasks.scheduling.NotificationSchedulerIntentService
import org.tasks.themes.TasksTheme
import org.tasks.ui.TaskEditControlFragment import org.tasks.ui.TaskEditControlFragment
import javax.inject.Inject import javax.inject.Inject
@ -76,57 +75,55 @@ class ReminderControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View = override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { val ringMode by remember { this@ReminderControlSet.ringMode }
val ringMode by remember { this@ReminderControlSet.ringMode } val hasReminderPermissions by rememberReminderPermissionState()
val hasReminderPermissions by rememberReminderPermissionState() val notificationPermissions = if (AndroidUtilities.atLeastTiramisu()) {
val notificationPermissions = if (AndroidUtilities.atLeastTiramisu()) { rememberPermissionState(
rememberPermissionState( Manifest.permission.POST_NOTIFICATIONS,
Manifest.permission.POST_NOTIFICATIONS, onPermissionResult = { success ->
onPermissionResult = { success -> if (success) {
if (success) { NotificationSchedulerIntentService.enqueueWork(context)
NotificationSchedulerIntentService.enqueueWork(context)
}
} }
)
} else {
null
}
val pickDateAndTime =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != RESULT_OK) return@rememberLauncherForActivityResult
val data = result.data ?: return@rememberLauncherForActivityResult
val timestamp =
data.getLongExtra(MyTimePickerDialog.EXTRA_TIMESTAMP, 0L)
val replace: Alarm? = data.getParcelableExtra(EXTRA_REPLACE)
replace?.let { viewModel.removeAlarm(it) }
viewModel.addAlarm(Alarm(time = timestamp, type = TYPE_DATE_TIME))
}
AlarmRow(
alarms = viewModel.selectedAlarms.collectAsStateWithLifecycle().value,
hasNotificationPermissions = hasReminderPermissions &&
(notificationPermissions == null || notificationPermissions.status == PermissionStatus.Granted),
fixNotificationPermissions = {
if (hasReminderPermissions) {
notificationPermissions?.launchPermissionRequest()
} else {
context.openReminderSettings()
}
},
ringMode = ringMode,
addAlarm = viewModel::addAlarm,
openRingType = this@ReminderControlSet::onClickRingType,
deleteAlarm = viewModel::removeAlarm,
pickDateAndTime = { replace ->
val timestamp = replace?.takeIf { it.type == TYPE_DATE_TIME }?.time
?: DateTimeUtils.newDateTime().noon().millis
pickDateAndTime.launch(
Intent(activity, DateAndTimePickerActivity::class.java)
.putExtra(DateAndTimePickerActivity.EXTRA_TIMESTAMP, timestamp)
.putExtra(EXTRA_REPLACE, replace)
)
} }
) )
} else {
null
} }
val pickDateAndTime =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode != RESULT_OK) return@rememberLauncherForActivityResult
val data = result.data ?: return@rememberLauncherForActivityResult
val timestamp =
data.getLongExtra(MyTimePickerDialog.EXTRA_TIMESTAMP, 0L)
val replace: Alarm? = data.getParcelableExtra(EXTRA_REPLACE)
replace?.let { viewModel.removeAlarm(it) }
viewModel.addAlarm(Alarm(time = timestamp, type = TYPE_DATE_TIME))
}
AlarmRow(
alarms = viewModel.selectedAlarms.collectAsStateWithLifecycle().value,
hasNotificationPermissions = hasReminderPermissions &&
(notificationPermissions == null || notificationPermissions.status == PermissionStatus.Granted),
fixNotificationPermissions = {
if (hasReminderPermissions) {
notificationPermissions?.launchPermissionRequest()
} else {
context.openReminderSettings()
}
},
ringMode = ringMode,
addAlarm = viewModel::addAlarm,
openRingType = this@ReminderControlSet::onClickRingType,
deleteAlarm = viewModel::removeAlarm,
pickDateAndTime = { replace ->
val timestamp = replace?.takeIf { it.type == TYPE_DATE_TIME }?.time
?: DateTimeUtils.newDateTime().noon().millis
pickDateAndTime.launch(
Intent(activity, DateAndTimePickerActivity::class.java)
.putExtra(DateAndTimePickerActivity.EXTRA_TIMESTAMP, timestamp)
.putExtra(EXTRA_REPLACE, replace)
)
}
)
} }
} }

@ -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.getRelativeDateTime
import org.tasks.kmp.org.tasks.time.getTimeString import org.tasks.kmp.org.tasks.time.getTimeString
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTimeUtils2.currentTimeMillis import org.tasks.time.DateTimeUtils2.currentTimeMillis
import org.tasks.time.withMillisOfDay import org.tasks.time.withMillisOfDay
import org.tasks.ui.TaskEditControlFragment import org.tasks.ui.TaskEditControlFragment
@ -49,42 +48,40 @@ class StartDateControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?) = override fun bind(parent: ViewGroup?) =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { val selectedDay = vm.selectedDay.collectAsStateWithLifecycle().value
val selectedDay = vm.selectedDay.collectAsStateWithLifecycle().value val selectedTime = vm.selectedTime.collectAsStateWithLifecycle().value
val selectedTime = vm.selectedTime.collectAsStateWithLifecycle().value StartDateRow(
StartDateRow( startDate = viewModel.startDate.collectAsStateWithLifecycle().value,
startDate = viewModel.startDate.collectAsStateWithLifecycle().value, selectedDay = selectedDay,
selectedDay = selectedDay, selectedTime = selectedTime,
selectedTime = selectedTime, hasDueDate = viewModel.dueDate.collectAsStateWithLifecycle().value > 0,
hasDueDate = viewModel.dueDate.collectAsStateWithLifecycle().value > 0, printDate = {
printDate = { runBlocking {
runBlocking { getRelativeDateTime(
getRelativeDateTime( selectedDay + selectedTime,
selectedDay + selectedTime, requireContext().is24HourFormat,
requireContext().is24HourFormat, DateStyle.FULL,
DateStyle.FULL, alwaysDisplayFullDate = preferences.alwaysDisplayFullDate
alwaysDisplayFullDate = preferences.alwaysDisplayFullDate )
) }
} },
}, onClick = {
onClick = { val fragmentManager = parentFragmentManager
val fragmentManager = parentFragmentManager if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) {
if (fragmentManager.findFragmentByTag(FRAG_TAG_DATE_PICKER) == null) { StartDatePicker.newDateTimePicker(
StartDatePicker.newDateTimePicker( this@StartDateControlSet,
this@StartDateControlSet, REQUEST_START_DATE,
REQUEST_START_DATE, vm.selectedDay.value,
vm.selectedDay.value, vm.selectedTime.value,
vm.selectedTime.value, preferences.getBoolean(
preferences.getBoolean( R.string.p_auto_dismiss_datetime_edit_screen,
R.string.p_auto_dismiss_datetime_edit_screen, false
false
)
) )
.show(fragmentManager, FRAG_TAG_DATE_PICKER) )
} .show(fragmentManager, FRAG_TAG_DATE_PICKER)
} }
) }
} )
} }
} }

@ -17,13 +17,32 @@ fun CheckBox(
onCompleteClick: () -> Unit, onCompleteClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
desaturate: Boolean, 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) { IconButton(onClick = onCompleteClick, modifier = modifier) {
Icon( Icon(
painter = painterResource(id = task.getCheckboxRes()), painter = painterResource(id = getCheckboxRes(isCompleted, isRecurring)),
tint = Color( tint = Color(
priorityColor( priorityColor(
priority = task.priority, priority = priority,
isDarkMode = isSystemInDarkTheme(), isDarkMode = isSystemInDarkTheme(),
desaturate = desaturate, desaturate = desaturate,
) )
@ -31,4 +50,4 @@ fun CheckBox(
contentDescription = null, contentDescription = null,
) )
} }
} }

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

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

@ -1,20 +1,16 @@
package org.tasks.compose.edit package org.tasks.compose.edit
import android.content.res.Configuration import android.content.res.Configuration
import android.text.InputType import androidx.compose.foundation.layout.Arrangement
import android.util.TypedValue import androidx.compose.foundation.layout.Column
import android.view.View import androidx.compose.foundation.layout.Spacer
import android.view.inputmethod.EditorInfo import androidx.compose.foundation.layout.height
import android.widget.EditText
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp 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.R
import org.tasks.compose.TaskEditRow import org.tasks.compose.TaskEditRow
import org.tasks.dialogs.Linkify import org.tasks.dialogs.Linkify
@ -33,46 +29,12 @@ fun DescriptionRow(
content = { content = {
Column(verticalArrangement = Arrangement.Center) { Column(verticalArrangement = Arrangement.Center) {
Spacer(modifier = Modifier.height(11.dp)) Spacer(modifier = Modifier.height(11.dp))
AndroidView( EditTextView(
modifier = Modifier text = text,
.fillMaxWidth() hint = stringResource(R.string.TEA_note_label),
.wrapContentHeight() onChanged = onChanged,
.padding(end = 16.dp), linkify = linkify,
factory = { context -> markdownProvider = markdownProvider,
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)
}
},
) )
Spacer(modifier = Modifier.height(11.dp)) 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, id = org.tasks.R.drawable.ic_subdirectory_arrow_right_black_24dp,
modifier = Modifier modifier = Modifier
.padding( .padding(
start = 16.dp, start = 4.dp,
top = 20.dp, top = 8.dp,
end = 20.dp, end = 8.dp,
bottom = 20.dp bottom = 8.dp
) )
.alpha(ContentAlpha.medium), .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.compose.edit.CalendarRow
import org.tasks.extensions.Context.toast import org.tasks.extensions.Context.toast
import org.tasks.preferences.PermissionChecker import org.tasks.preferences.PermissionChecker
import org.tasks.themes.TasksTheme
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -45,34 +44,32 @@ class CalendarControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View = override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { CalendarRow(
CalendarRow( eventUri = viewModel.eventUri.collectAsStateWithLifecycle().value,
eventUri = viewModel.eventUri.collectAsStateWithLifecycle().value, selectedCalendar = viewModel.selectedCalendar.collectAsStateWithLifecycle().value?.let {
selectedCalendar = viewModel.selectedCalendar.collectAsStateWithLifecycle().value?.let { calendarProvider.getCalendar(it)?.name
calendarProvider.getCalendar(it)?.name },
}, onClick = {
onClick = { if (viewModel.eventUri.value.isNullOrBlank()) {
if (viewModel.eventUri.value.isNullOrBlank()) { CalendarPicker
CalendarPicker .newCalendarPicker(
.newCalendarPicker( requireParentFragment(),
requireParentFragment(), TaskEditFragment.REQUEST_CODE_PICK_CALENDAR,
TaskEditFragment.REQUEST_CODE_PICK_CALENDAR, viewModel.selectedCalendar.value,
viewModel.selectedCalendar.value, )
) .show(
.show( requireParentFragment().parentFragmentManager,
requireParentFragment().parentFragmentManager, TaskEditFragment.FRAG_TAG_CALENDAR_PICKER
TaskEditFragment.FRAG_TAG_CALENDAR_PICKER )
) } else {
} else { openCalendarEvent()
openCalendarEvent()
}
},
clear = {
viewModel.selectedCalendar.value = null
viewModel.eventUri.value = null
} }
) },
} clear = {
viewModel.selectedCalendar.value = null
viewModel.eventUri.value = null
}
)
} }
} }

@ -4,9 +4,9 @@ import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import org.tasks.data.entity.Task
import dagger.hilt.android.qualifiers.ActivityContext import dagger.hilt.android.qualifiers.ActivityContext
import org.tasks.R import org.tasks.R
import org.tasks.data.entity.Task
import org.tasks.themes.ColorProvider import org.tasks.themes.ColorProvider
import javax.inject.Inject import javax.inject.Inject
@ -24,7 +24,9 @@ class CheckBoxProvider @Inject constructor(
} }
companion object { 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 isCompleted -> R.drawable.ic_outline_check_box_24px
isRecurring -> R.drawable.ic_outline_repeat_24px isRecurring -> R.drawable.ic_outline_repeat_24px
else -> R.drawable.ic_outline_check_box_outline_blank_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
import org.tasks.preferences.PermissionChecker.backgroundPermissions import org.tasks.preferences.PermissionChecker.backgroundPermissions
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.themes.TasksTheme
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -85,27 +84,25 @@ class LocationControlSet : TaskEditControlFragment() {
override fun bind(parent: ViewGroup?): View = override fun bind(parent: ViewGroup?): View =
(parent as ComposeView).apply { (parent as ComposeView).apply {
setContent { setContent {
TasksTheme { val hasPermissions =
val hasPermissions = rememberMultiplePermissionsState(permissions = backgroundPermissions())
rememberMultiplePermissionsState(permissions = backgroundPermissions()) .allPermissionsGranted
.allPermissionsGranted LocationRow(
LocationRow( location = viewModel.selectedLocation.collectAsStateWithLifecycle().value,
location = viewModel.selectedLocation.collectAsStateWithLifecycle().value, hasPermissions = hasPermissions,
hasPermissions = hasPermissions, onClick = this@LocationControlSet::onRowClick,
onClick = this@LocationControlSet::onRowClick, openGeofenceOptions = {
openGeofenceOptions = { if (hasPermissions) {
if (hasPermissions) { showGeofenceOptions()
showGeofenceOptions() } else {
} else { newLocationPermissionDialog(
newLocationPermissionDialog( this@LocationControlSet,
this@LocationControlSet, REQUEST_LOCATION_PERMISSIONS
REQUEST_LOCATION_PERMISSIONS )
) .show(parentFragmentManager, FRAG_TAG_REQUEST_LOCATION)
.show(parentFragmentManager, FRAG_TAG_REQUEST_LOCATION)
}
} }
) }
} )
} }
} }

@ -25,7 +25,6 @@ import org.tasks.preferences.Preferences
import org.tasks.tasklist.SectionedDataSource import org.tasks.tasklist.SectionedDataSource
import org.tasks.tasklist.TasksResults import org.tasks.tasklist.TasksResults
import org.tasks.themes.ColorProvider import org.tasks.themes.ColorProvider
import org.tasks.themes.TasksTheme
import org.tasks.time.DateTimeUtils2.currentTimeMillis import org.tasks.time.DateTimeUtils2.currentTimeMillis
import javax.inject.Inject import javax.inject.Inject
@ -55,39 +54,37 @@ class SubtaskControlSet : TaskEditControlFragment() {
(parent as ComposeView).apply { (parent as ComposeView).apply {
listViewModel = ViewModelProvider(requireParentFragment())[TaskListViewModel::class.java] listViewModel = ViewModelProvider(requireParentFragment())[TaskListViewModel::class.java]
setContent { setContent {
TasksTheme { SubtaskRow(
SubtaskRow( originalFilter = viewModel.originalList,
originalFilter = viewModel.originalList, filter = viewModel.selectedList.collectAsStateWithLifecycle().value,
filter = viewModel.selectedList.collectAsStateWithLifecycle().value, hasParent = viewModel.hasParent,
hasParent = viewModel.hasParent, desaturate = preferences.desaturateDarkMode,
desaturate = preferences.desaturateDarkMode, existingSubtasks = if (viewModel.isNew) {
existingSubtasks = if (viewModel.isNew) { TasksResults.Results(SectionedDataSource())
TasksResults.Results(SectionedDataSource()) } else {
} else { listViewModel.state.collectAsStateWithLifecycle().value.tasks
listViewModel.state.collectAsStateWithLifecycle().value.tasks },
}, newSubtasks = viewModel.newSubtasks.collectAsStateWithLifecycle().value,
newSubtasks = viewModel.newSubtasks.collectAsStateWithLifecycle().value, openSubtask = this@SubtaskControlSet::openSubtask,
openSubtask = this@SubtaskControlSet::openSubtask, completeExistingSubtask = this@SubtaskControlSet::complete,
completeExistingSubtask = this@SubtaskControlSet::complete, toggleSubtask = this@SubtaskControlSet::toggleSubtask,
toggleSubtask = this@SubtaskControlSet::toggleSubtask, addSubtask = this@SubtaskControlSet::addSubtask,
addSubtask = this@SubtaskControlSet::addSubtask, completeNewSubtask = {
completeNewSubtask = { viewModel.newSubtasks.value =
viewModel.newSubtasks.value = ArrayList(viewModel.newSubtasks.value).apply {
ArrayList(viewModel.newSubtasks.value).apply { val modified = it.copy(
val modified = it.copy( completionDate = if (it.isCompleted) 0 else currentTimeMillis()
completionDate = if (it.isCompleted) 0 else currentTimeMillis() )
) set(indexOf(it), modified)
set(indexOf(it), modified) }
} },
}, deleteSubtask = {
deleteSubtask = { viewModel.newSubtasks.value =
viewModel.newSubtasks.value = ArrayList(viewModel.newSubtasks.value).apply {
ArrayList(viewModel.newSubtasks.value).apply { remove(it)
remove(it) }
} }
} )
)
}
} }
} }

@ -102,11 +102,12 @@ class TaskEditViewModel @Inject constructor(
val isNew = task.isNew val isNew = task.isNew
var showBeastModeHint = MutableStateFlow(!preferences.shownBeastModeHint)
var creationDate: Long = task.creationDate var creationDate: Long = task.creationDate
var modificationDate: Long = task.modificationDate var modificationDate: Long = task.modificationDate
var completionDate: Long = task.completionDate var completionDate: Long = task.completionDate
var title: String? = task.title var title: String? = task.title
var completed: Boolean = task.isCompleted var completed = MutableStateFlow(task.isCompleted)
var priority = MutableStateFlow(task.priority) var priority = MutableStateFlow(task.priority)
var description: String? = task.notes.stripCarriageReturns() var description: String? = task.notes.stripCarriageReturns()
val recurrence = MutableStateFlow(task.recurrence) val recurrence = MutableStateFlow(task.recurrence)
@ -217,7 +218,7 @@ class TaskEditViewModel @Inject constructor(
fun hasChanges(): Boolean = fun hasChanges(): Boolean =
(task.title != title || (isNew && title?.isNotBlank() == true)) || (task.title != title || (isNew && title?.isNotBlank() == true)) ||
task.isCompleted != completed || task.isCompleted != completed.value ||
task.dueDate != dueDate.value || task.dueDate != dueDate.value ||
task.priority != priority.value || task.priority != priority.value ||
if (task.notes.isNullOrBlank()) { if (task.notes.isNullOrBlank()) {
@ -399,10 +400,10 @@ class TaskEditViewModel @Inject constructor(
.let { taskAttachmentDao.insert(it) } .let { taskAttachmentDao.insert(it) }
} }
if (task.isCompleted != completed) { if (task.isCompleted != completed.value) {
taskCompleter.setComplete(task, completed) taskCompleter.setComplete(task, completed.value)
if (task.isCompleted) { 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 { init {
viewModelScope.launch { viewModelScope.launch {
taskAttachmentDao.getAttachments(task.id).let { attachments -> 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="custom_filter_criteria">معايير التصفية</string>
<string name="settings_default">افتراضي</string> <string name="settings_default">افتراضي</string>
<string name="widget_id">معرف ويدجت: %d</string> <string name="widget_id">معرف ويدجت: %d</string>
<string name="hide_check_button">إخفاء مربع الاختيار</string>
<string name="calendar_event_created">تم إنشاء حدث التقويم ل%s</string> <string name="calendar_event_created">تم إنشاء حدث التقويم ل%s</string>
<string name="auto_dismiss_datetime_summary">إغلاق منتقي التاريخ والوقت بعد تحديد التاريخ أو الوقت</string> <string name="auto_dismiss_datetime_summary">إغلاق منتقي التاريخ والوقت بعد تحديد التاريخ أو الوقت</string>
<string name="auto_dismiss_datetime_widget_summary">الغلق التلقائي عند الانتقاء من ويدجت</string> <string name="auto_dismiss_datetime_widget_summary">الغلق التلقائي عند الانتقاء من ويدجت</string>

@ -593,7 +593,6 @@
<string name="desaturate_colors_summary_on">При тъмите теми цветовете ще бъдат с намалена наситеност</string> <string name="desaturate_colors_summary_on">При тъмите теми цветовете ще бъдат с намалена наситеност</string>
<string name="sort_created_group">Създадена %s</string> <string name="sort_created_group">Създадена %s</string>
<string name="desaturate_colors_summary_off">При тъмите теми цветовете няма да бъдат променяни</string> <string name="desaturate_colors_summary_off">При тъмите теми цветовете няма да бъдат променяни</string>
<string name="hide_check_button">Скриване на бутона за отмятане</string>
<string name="sort_modified_group">Променена %s</string> <string name="sort_modified_group">Променена %s</string>
<string name="github_sponsor">Дарител</string> <string name="github_sponsor">Дарител</string>
<string name="tasks_org_account_required">Необходим е профил в Tasks.org</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="custom_filter_criteria">Podmínky filtru</string>
<string name="compact">Kompaktní</string> <string name="compact">Kompaktní</string>
<string name="settings_default">Výchozí</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="share">Sdílet</string>
<string name="select_all">Vybrat vše</string> <string name="select_all">Vybrat vše</string>
<string name="calendar_event_created">Událost v kalendáři vytvořena pro %s</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="compact">Kompakt</string>
<string name="settings_default">Standard</string> <string name="settings_default">Standard</string>
<string name="widget_id">Widget-ID: %d</string> <string name="widget_id">Widget-ID: %d</string>
<string name="hide_check_button">Skjul afkrydsningsknap</string>
<string name="share">Del</string> <string name="share">Del</string>
<string name="select_all">Vælg alle</string> <string name="select_all">Vælg alle</string>
<string name="calendar_event_created">Kalenderbegivenhed oprettet for %s</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="calendar_event_created">Kalendereintrag für %s erstellt</string>
<string name="select_all">Alles auswählen</string> <string name="select_all">Alles auswählen</string>
<string name="share">Teilen</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="widget_show_dividers">Trennlinien anzeigen</string>
<string name="opacity_footer">Deckkraft der Fußzeile</string> <string name="opacity_footer">Deckkraft der Fußzeile</string>
<string name="opacity_row">Deckkraft der Zeilen</string> <string name="opacity_row">Deckkraft der Zeilen</string>

@ -604,7 +604,6 @@
<string name="invalid_backup_file">Nevalida savkopio</string> <string name="invalid_backup_file">Nevalida savkopio</string>
<string name="davx5_selection_description">Sinkronigi viajn taskojn kun la DAVx⁵ programeto</string> <string name="davx5_selection_description">Sinkronigi viajn taskojn kun la DAVx⁵ programeto</string>
<string name="navigation_drawer">Naviga tirkesto</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_any_due_date">Ajna limdato</string>
<string name="filter_high_priority">Grava</string> <string name="filter_high_priority">Grava</string>
<string name="filter_medium_priority">Meza prioritato</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="calendar_event_created">Calendario de eventos creado para %s</string>
<string name="share">Compartir</string> <string name="share">Compartir</string>
<string name="select_all">Seleccionar todo</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="compact">Compacto</string>
<string name="settings_default">Predefinido</string> <string name="settings_default">Predefinido</string>
<string name="widget_id">Widget ID: %d</string> <string name="widget_id">Widget ID: %d</string>

@ -456,7 +456,6 @@
<string name="no_date">Datarik ez</string> <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_summary">Itxi data/ordu hautatzailea behin data eta ordua hautatuta</string>
<string name="auto_dismiss_datetime">Automatikoki itxi data/ordu hautatzailea</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="share">Partekatu</string>
<string name="select_all">Hautatu denak</string> <string name="select_all">Hautatu denak</string>
<string name="calendar_event_created">%s gertaera sortu da egutegian</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="add_tags">Lisää tunniste</string>
<string name="filter_any_due_date">Mikä tahansa määräpäivä</string> <string name="filter_any_due_date">Mikä tahansa määräpäivä</string>
<string name="settings_default">Oletusarvo</string> <string name="settings_default">Oletusarvo</string>
<string name="hide_check_button">Piilota valinta painike</string>
<string name="share">Jaa</string> <string name="share">Jaa</string>
<string name="select_all">Valitse kaikki</string> <string name="select_all">Valitse kaikki</string>
<string name="widget_show_menu">Näytä valikko</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="calendar_event_created">Évènement de calendrier créé pour %s</string>
<string name="share">Partager</string> <string name="share">Partager</string>
<string name="select_all">Tout sélectionner</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="compact">Compacte</string>
<string name="settings_default">Par défaut</string> <string name="settings_default">Par défaut</string>
<string name="widget_id">Identifiant du widget: %d</string> <string name="widget_id">Identifiant du widget: %d</string>

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

@ -535,7 +535,6 @@
<string name="compact">Kompaktno</string> <string name="compact">Kompaktno</string>
<string name="settings_default">Standardno</string> <string name="settings_default">Standardno</string>
<string name="widget_id">Widget ID: %d</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="share">Dijeli</string>
<string name="select_all">Odaberi sve</string> <string name="select_all">Odaberi sve</string>
<string name="calendar_event_created">Kalendarski događaj stvoren za %s</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="calendar_event_created">Naptár esemény létrehozva: %s</string>
<string name="share">Megosztás</string> <string name="share">Megosztás</string>
<string name="select_all">Az összes kiválasztása</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="compact">Kompakt</string>
<string name="settings_default">Alapértelmezett</string> <string name="settings_default">Alapértelmezett</string>
<string name="widget_id">Widget azonosító: %d</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="more_notification_settings_summary">Nada dering, getar, dan lainnya</string>
<string name="actfm_picture_clear">Hapus Gambar</string> <string name="actfm_picture_clear">Hapus Gambar</string>
<string name="settings_default">Bawaan</string> <string name="settings_default">Bawaan</string>
<string name="hide_check_button">Sembunyikan tombol centang</string>
<string name="share">Bagikan</string> <string name="share">Bagikan</string>
<string name="select_all">Pilih Semua</string> <string name="select_all">Pilih Semua</string>
<string name="calendar_event_created">Acara kalender dibuat untuk %s</string> <string name="calendar_event_created">Acara kalender dibuat untuk %s</string>

@ -501,7 +501,6 @@
<string name="compact">Compatto</string> <string name="compact">Compatto</string>
<string name="settings_default">Predefinito</string> <string name="settings_default">Predefinito</string>
<string name="widget_id">ID widget: %d</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_footer">Opacità piè di pagina</string>
<string name="opacity_row">Opacità riga</string> <string name="opacity_row">Opacità riga</string>
<string name="opacity_header">Opacità intestazione</string> <string name="opacity_header">Opacità intestazione</string>

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

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

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

@ -530,7 +530,6 @@
<string name="display_name">Rodomas pavadinimas</string> <string name="display_name">Rodomas pavadinimas</string>
<string name="date_picker_multiple">Keleta</string> <string name="date_picker_multiple">Keleta</string>
<string name="compact">Kompaktiška</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="navigation_drawer">Navigacijos parankinės juosta</string>
<string name="foreground_location">Vietos nustatymas</string> <string name="foreground_location">Vietos nustatymas</string>
<string name="background_location">Foninis 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="widget_show_dividers">Vis inndelere</string>
<string name="filter_overdue">Forsinket</string> <string name="filter_overdue">Forsinket</string>
<string name="custom_filter_criteria">Filterkriterium</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="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_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> <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="calendar_event_created">Kalender-item aangemaakt voor %s</string>
<string name="share">Taken delen</string> <string name="share">Taken delen</string>
<string name="select_all">Alles selecteren</string> <string name="select_all">Alles selecteren</string>
<string name="hide_check_button">Selectievakje verbergen</string>
<string name="compact">Compact</string> <string name="compact">Compact</string>
<string name="settings_default">Standaardwaarde</string> <string name="settings_default">Standaardwaarde</string>
<string name="widget_id">Widget ID: %d</string> <string name="widget_id">Widget ID: %d</string>

@ -468,7 +468,6 @@
<string name="compact">Kompaktowy</string> <string name="compact">Kompaktowy</string>
<string name="settings_default">Domyślny</string> <string name="settings_default">Domyślny</string>
<string name="widget_id">Identyfikator widżetu: %d</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="share">Udostępnij</string>
<string name="select_all">Zaznacz wszystko</string> <string name="select_all">Zaznacz wszystko</string>
<string name="calendar_event_created">Wydarzenie kalendarzowe utworzone dla %s</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="open_map">Abrir mapa</string>
<string name="choose_new_location">Escolher nova localização</string> <string name="choose_new_location">Escolher nova localização</string>
<string name="widget_id">ID do widget: %d</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="share">Compartilhar</string>
<string name="select_all">Selecionar todos</string> <string name="select_all">Selecionar todos</string>
<string name="calendar_event_created">Evento de calendário criado para %s</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="settings_default">Predefinição</string>
<string name="widget_show_menu">Mostrar menu</string> <string name="widget_show_menu">Mostrar menu</string>
<string name="widget_id">ID do widget: %d</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="share">Partilhar</string>
<string name="select_all">Selecionar todos</string> <string name="select_all">Selecionar todos</string>
<string name="calendar_event_created">Evento de calendário criado para %s</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="custom_filter_criteria">Criterii de filtrare</string>
<string name="settings_default">Implicit</string> <string name="settings_default">Implicit</string>
<string name="widget_id">ID-ul aplicației: %d</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="share">Distribuie</string>
<string name="select_all">Selectează toate</string> <string name="select_all">Selectează toate</string>
<string name="calendar_event_created">Eveniment calendaristic creat pentru %s</string> <string name="calendar_event_created">Eveniment calendaristic creat pentru %s</string>

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

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

@ -548,7 +548,6 @@
<string name="filter_overdue">Försenad</string> <string name="filter_overdue">Försenad</string>
<string name="custom_filter_criteria">Filterkriterier</string> <string name="custom_filter_criteria">Filterkriterier</string>
<string name="widget_id">Widget-ID: %d</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="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_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> <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="compact">கச்சிதமான</string>
<string name="settings_default">இயல்புநிலை</string> <string name="settings_default">இயல்புநிலை</string>
<string name="widget_id">விட்ஜெட் ஐடி: %d</string> <string name="widget_id">விட்ஜெட் ஐடி: %d</string>
<string name="hide_check_button">சோதனை பொத்தானை மறைக்க</string>
<string name="share">பகிர்</string> <string name="share">பகிர்</string>
<string name="select_all">அனைத்தையும் தெரிவுசெய்</string> <string name="select_all">அனைத்தையும் தெரிவுசெய்</string>
<string name="calendar_event_created">%s க்கு காலண்டர் நிகழ்வு உருவாக்கப்பட்டது</string> <string name="calendar_event_created">%s க்கு காலண்டர் நிகழ்வு உருவாக்கப்பட்டது</string>

@ -536,7 +536,6 @@
<string name="compact">ข้อตกลง</string> <string name="compact">ข้อตกลง</string>
<string name="settings_default">ค่าเริ่มต้น</string> <string name="settings_default">ค่าเริ่มต้น</string>
<string name="widget_id">รหัสวิดเจ็ต: %d</string> <string name="widget_id">รหัสวิดเจ็ต: %d</string>
<string name="hide_check_button">ซ่อนปุ่มตรวจสอบ</string>
<string name="share">ใช้ร่วมกัน</string> <string name="share">ใช้ร่วมกัน</string>
<string name="select_all">เลือกทั้งหมด</string> <string name="select_all">เลือกทั้งหมด</string>
<string name="calendar_event_created">เหตุการณ์ในปฏิทินที่สร้างสําหรับ %s</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_only">Yalnızca metin</string>
<string name="chip_appearance_text_and_icon">Metin ve simge</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="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="share">Paylaş</string>
<string name="select_all">Tümünü seç</string> <string name="select_all">Tümünü seç</string>
<string name="compact">Sıkı</string> <string name="compact">Sıkı</string>

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

@ -175,7 +175,6 @@
<string name="compact">Nhỏ gọn</string> <string name="compact">Nhỏ gọn</string>
<string name="settings_default">Mặc định</string> <string name="settings_default">Mặc định</string>
<string name="widget_id">ID tiện ích: %d</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="share">Chia sẻ</string>
<string name="select_all">Chọn tất cả</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> <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="share">分享</string>
<string name="select_all">选中全部</string> <string name="select_all">选中全部</string>
<string name="calendar_event_created">已为 %s 创建日历事件</string> <string name="calendar_event_created">已为 %s 创建日历事件</string>
<string name="hide_check_button">隐藏检查按钮</string>
<string name="compact">紧凑</string> <string name="compact">紧凑</string>
<string name="settings_default">默认</string> <string name="settings_default">默认</string>
<string name="widget_id">部件ID%d</string> <string name="widget_id">部件ID%d</string>

@ -331,7 +331,6 @@
<string name="custom_filter_criteria">編輯器標準</string> <string name="custom_filter_criteria">編輯器標準</string>
<string name="compact"></string> <string name="compact"></string>
<string name="settings_default">預設</string> <string name="settings_default">預設</string>
<string name="hide_check_button">隱藏勾選鈕</string>
<string name="share">分享</string> <string name="share">分享</string>
<string name="select_all">選擇全部</string> <string name="select_all">選擇全部</string>
<string name="auto_dismiss_datetime_summary">選擇日期或時間後關閉日期時間選擇器</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_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_list_screen">auto_dismiss_datetime_list_screen</string>
<string name="p_auto_dismiss_datetime_widget">auto_dismiss_datetime_widget</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_show_whats_new">show_whats_new</string>
<string name="p_just_updated">just_updated</string> <string name="p_just_updated">just_updated</string>
<string name="p_last_review_request">last_review_request</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="calendar_event_created">Calendar event created for %s</string>
<string name="select_all">Select all</string> <string name="select_all">Select all</string>
<string name="share">Share</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="widget_id">Widget ID: %d</string>
<string name="settings_default">Default</string> <string name="settings_default">Default</string>
<string name="compact">Compact</string> <string name="compact">Compact</string>

@ -24,11 +24,6 @@
android:key="@string/p_back_button_saves_task" android:key="@string/p_back_button_saves_task"
android:title="@string/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 <SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"
android:key="@string/p_show_task_edit_comments" android:key="@string/p_show_task_edit_comments"

Loading…
Cancel
Save