diff --git a/app/src/androidTest/java/com/todoroo/astrid/service/QuickAddMarkupTest.kt b/app/src/androidTest/java/com/todoroo/astrid/service/QuickAddMarkupTest.kt index b6984c6d5..d6ee05366 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/service/QuickAddMarkupTest.kt +++ b/app/src/androidTest/java/com/todoroo/astrid/service/QuickAddMarkupTest.kt @@ -9,9 +9,10 @@ import com.todoroo.astrid.data.Task import com.todoroo.astrid.utility.TitleParser import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.UninstallModules +import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Test -import org.tasks.data.TagDataDaoBlocking +import org.tasks.data.TagDataDao import org.tasks.injection.InjectingTestCase import org.tasks.injection.ProductionModule import java.util.* @@ -21,7 +22,7 @@ import javax.inject.Inject @HiltAndroidTest class QuickAddMarkupTest : InjectingTestCase() { private val tags = ArrayList() - @Inject lateinit var tagDataDao: TagDataDaoBlocking + @Inject lateinit var tagDataDao: TagDataDao private var task: Task? = null @@ -81,7 +82,7 @@ class QuickAddMarkupTest : InjectingTestCase() { assertEquals(title, task!!.title) } - private fun whenTitleIs(title: String) { + private fun whenTitleIs(title: String) = runBlocking { task = Task() task!!.title = title tags.clear() diff --git a/app/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.kt b/app/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.kt index c411191d9..deda0f817 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.kt +++ b/app/src/androidTest/java/com/todoroo/astrid/service/TitleParserTest.kt @@ -11,11 +11,12 @@ import com.todoroo.astrid.data.Task import com.todoroo.astrid.utility.TitleParser import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.UninstallModules +import kotlinx.coroutines.runBlocking import org.junit.Assert.* import org.junit.Before import org.junit.Test import org.tasks.R -import org.tasks.data.TagDataDaoBlocking +import org.tasks.data.TagDataDao import org.tasks.date.DateTimeUtils import org.tasks.injection.InjectingTestCase import org.tasks.injection.ProductionModule @@ -26,7 +27,7 @@ import javax.inject.Inject @UninstallModules(ProductionModule::class) @HiltAndroidTest class TitleParserTest : InjectingTestCase() { - @Inject lateinit var tagDataDao: TagDataDaoBlocking + @Inject lateinit var tagDataDao: TagDataDao @Inject lateinit var preferences: Preferences @Inject lateinit var taskCreator: TaskCreator @@ -41,7 +42,7 @@ class TitleParserTest : InjectingTestCase() { * repeat, no lists */ @Test - fun testNoRegexes() { + fun testNoRegexes() = runBlocking { val task = taskCreator.basicQuickAddTask("Jog") val nothing = Task() assertFalse(task.hasDueTime()) @@ -147,13 +148,13 @@ class TitleParserTest : InjectingTestCase() { } } - private fun insertTitleAddTask(title: String): Task { - return taskCreator.createWithValues(title) + private fun insertTitleAddTask(title: String): Task = runBlocking { + taskCreator.createWithValues(title) } // ----------------Days begin----------------// @Test - fun testDays() { + fun testDays() = runBlocking { val today = Calendar.getInstance() var title = "Jog today" var task = taskCreator.createWithValues(title) @@ -182,7 +183,7 @@ class TitleParserTest : InjectingTestCase() { // ----------------Priority begin----------------// /** tests all words using priority 0 */ @Test - fun testPriority0() { + fun testPriority0() = runBlocking { val acceptedStrings = arrayOf("priority 0", "least priority", "lowest priority", "bang 0") for (acceptedString in acceptedStrings) { val title = "Jog $acceptedString" @@ -197,7 +198,7 @@ class TitleParserTest : InjectingTestCase() { } @Test - fun testPriority1() { + fun testPriority1() = runBlocking { val acceptedStringsAtEnd = arrayOf("priority 1", "low priority", "bang", "bang 1") val acceptedStringsAnywhere = arrayOf("!1", "!") var task: Task @@ -222,7 +223,7 @@ class TitleParserTest : InjectingTestCase() { } @Test - fun testPriority2() { + fun testPriority2() = runBlocking { val acceptedStringsAtEnd = arrayOf("priority 2", "high priority", "bang bang", "bang 2") val acceptedStringsAnywhere = arrayOf("!2", "!!") for (acceptedStringAtEnd in acceptedStringsAtEnd) { @@ -244,7 +245,7 @@ class TitleParserTest : InjectingTestCase() { } @Test - fun testPriority3() { + fun testPriority3() = runBlocking { val acceptedStringsAtEnd = arrayOf( "priority 3", "highest priority", @@ -274,7 +275,7 @@ class TitleParserTest : InjectingTestCase() { // ----------------Repeats begin----------------// /** test daily repeat from due date, but with no due date set */ @Test - fun testDailyWithNoDueDate() { + fun testDailyWithNoDueDate() = runBlocking { var title = "Jog daily" var task = taskCreator.createWithValues(title) val rrule = RRule() @@ -300,7 +301,7 @@ class TitleParserTest : InjectingTestCase() { /** test weekly repeat from due date, with no due date & time set */ @Test - fun testWeeklyWithNoDueDate() { + fun testWeeklyWithNoDueDate() = runBlocking { var title = "Jog weekly" var task = taskCreator.createWithValues(title) val rrule = RRule() @@ -326,7 +327,7 @@ class TitleParserTest : InjectingTestCase() { /** test hourly repeat from due date, with no due date but no time */ @Test - fun testMonthlyFromNoDueDate() { + fun testMonthlyFromNoDueDate() = runBlocking { var title = "Jog monthly" var task = taskCreator.createWithValues(title) val rrule = RRule() @@ -351,7 +352,7 @@ class TitleParserTest : InjectingTestCase() { } @Test - fun testDailyFromDueDate() { + fun testDailyFromDueDate() = runBlocking { var title = "Jog daily starting from today" var task = taskCreator.createWithValues(title) val rrule = RRule() @@ -373,7 +374,7 @@ class TitleParserTest : InjectingTestCase() { } @Test - fun testWeeklyFromDueDate() { + fun testWeeklyFromDueDate() = runBlocking { var title = "Jog weekly starting from today" var task = taskCreator.createWithValues(title) val rrule = RRule() @@ -397,7 +398,7 @@ class TitleParserTest : InjectingTestCase() { // ----------------Tags begin----------------// /** tests all words using priority 0 */ @Test - fun testTagsPound() { + fun testTagsPound() = runBlocking { val acceptedStrings = arrayOf("#tag", "#a", "#(a cool tag)", "#(cool)") var task: Task for (acceptedString in acceptedStrings) { @@ -414,7 +415,7 @@ class TitleParserTest : InjectingTestCase() { /** tests all words using priority 0 */ @Test - fun testTagsAt() { + fun testTagsAt() = runBlocking { val acceptedStrings = arrayOf("@tag", "@a", "@(a cool tag)", "@(cool)") var task: Task for (acceptedString in acceptedStrings) { diff --git a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt index e6dd08f46..3df509ef4 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt @@ -148,7 +148,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl navigationDrawer.closeDrawer() } - private fun getTaskToLoad(filter: Filter?): Task? { + private suspend fun getTaskToLoad(filter: Filter?): Task? { val intent = intent if (intent.isFromHistory) { return null @@ -165,7 +165,7 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl return null } - private fun openTask(filter: Filter?) { + private fun openTask(filter: Filter?) = lifecycleScope.launch { val task = getTaskToLoad(filter) when { task != null -> onTaskListItemClicked(task) @@ -344,30 +344,28 @@ class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandl private val nightMode: Int get() = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK - override fun onTaskListItemClicked(task: Task?) { + override suspend fun onTaskListItemClicked(task: Task?) { AndroidUtilities.assertMainThread() if (task == null) { return } - lifecycleScope.launchWhenResumed { - taskEditFragment?.let { - it.editViewModel.cleared.removeObservers(this@MainActivity) - it.save() - } - clearUi() - val fragment = newTaskEditFragment( - task, - defaultFilterProvider.getList(task), - locationDao.getLocation(task, preferences), - tagDataDao.getTags(task), - alarmDao.getAlarms(task), - filterColor) - supportFragmentManager.beginTransaction() - .replace(R.id.detail, fragment, TaskEditFragment.TAG_TASKEDIT_FRAGMENT) - .addToBackStack(TaskEditFragment.TAG_TASKEDIT_FRAGMENT) - .commit() - showDetailFragment() + taskEditFragment?.let { + it.editViewModel.cleared.removeObservers(this@MainActivity) + it.save() } + clearUi() + val fragment = newTaskEditFragment( + task, + defaultFilterProvider.getList(task), + locationDao.getLocation(task, preferences), + tagDataDao.getTags(task), + alarmDao.getAlarms(task), + filterColor) + supportFragmentManager.beginTransaction() + .replace(R.id.detail, fragment, TaskEditFragment.TAG_TASKEDIT_FRAGMENT) + .addToBackStack(TaskEditFragment.TAG_TASKEDIT_FRAGMENT) + .commit() + showDetailFragment() } override fun onNavigationIconClicked() { diff --git a/app/src/main/java/com/todoroo/astrid/activity/ShareLinkActivity.kt b/app/src/main/java/com/todoroo/astrid/activity/ShareLinkActivity.kt index e651cdfe8..99803435e 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/ShareLinkActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/ShareLinkActivity.kt @@ -4,12 +4,14 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import androidx.lifecycle.lifecycleScope import com.google.common.collect.Lists import com.google.common.io.Files import com.todoroo.astrid.data.Task import com.todoroo.astrid.service.TaskCreator import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.launch import org.tasks.Strings.isNullOrEmpty import org.tasks.data.TaskAttachment import org.tasks.files.FileHelper @@ -35,31 +37,39 @@ class ShareLinkActivity : InjectingAppCompatActivity() { super.onCreate(savedInstanceState) val intent = intent val action = intent.action - if (Intent.ACTION_PROCESS_TEXT == action) { - val text = intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT) - if (text != null) { - val task = taskCreator.createWithValues(text.toString()) + when { + Intent.ACTION_PROCESS_TEXT == action -> lifecycleScope.launch { + val text = intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT) + if (text != null) { + val task = taskCreator.createWithValues(text.toString()) + editTask(task) + } + finish() + } + Intent.ACTION_SEND == action -> lifecycleScope.launch { + val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT) + val task = taskCreator.createWithValues(subject) + task.notes = intent.getStringExtra(Intent.EXTRA_TEXT) + if (hasAttachments(intent)) { + task.putTransitory(TaskAttachment.KEY, copyAttachment(intent)) + } editTask(task) + finish() } - } else if (Intent.ACTION_SEND == action) { - val subject = intent.getStringExtra(Intent.EXTRA_SUBJECT) - val task = taskCreator.createWithValues(subject) - task.notes = intent.getStringExtra(Intent.EXTRA_TEXT) - if (hasAttachments(intent)) { - task.putTransitory(TaskAttachment.KEY, copyAttachment(intent)) + Intent.ACTION_SEND_MULTIPLE == action -> lifecycleScope.launch { + val task = taskCreator.createWithValues(intent.getStringExtra(Intent.EXTRA_SUBJECT)) + task.notes = intent.getStringExtra(Intent.EXTRA_TEXT) + if (hasAttachments(intent)) { + task.putTransitory(TaskAttachment.KEY, copyMultipleAttachments(intent)) + } + editTask(task) + finish() } - editTask(task) - } else if (Intent.ACTION_SEND_MULTIPLE == action) { - val task = taskCreator.createWithValues(intent.getStringExtra(Intent.EXTRA_SUBJECT)) - task.notes = intent.getStringExtra(Intent.EXTRA_TEXT) - if (hasAttachments(intent)) { - task.putTransitory(TaskAttachment.KEY, copyMultipleAttachments(intent)) + else -> { + Timber.e("Unhandled intent: %s", intent) + finish() } - editTask(task) - } else { - Timber.e("Unhandled intent: %s", intent) } - finish() } private fun editTask(task: Task) { diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt index d7bc9b77b..f7068533d 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.kt @@ -420,11 +420,13 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL @OnClick(R.id.fab) fun createNewTask() { - shortcutManager.reportShortcutUsed(ShortcutManager.SHORTCUT_NEW_TASK) - onTaskListItemClicked(addTask("")) + lifecycleScope.launch { + shortcutManager.reportShortcutUsed(ShortcutManager.SHORTCUT_NEW_TASK) + onTaskListItemClicked(addTask("")) + } } - private fun addTask(title: String): Task { + private suspend fun addTask(title: String): Task { return taskCreator.createWithValues(filter, title) } @@ -517,12 +519,14 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { VOICE_RECOGNITION_REQUEST_CODE -> if (resultCode == Activity.RESULT_OK) { - val match: List? = data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) - if (match != null && match.isNotEmpty() && match[0].isNotEmpty()) { - var recognizedSpeech = match[0] - recognizedSpeech = (recognizedSpeech.substring(0, 1).toUpperCase() - + recognizedSpeech.substring(1).toLowerCase()) - onTaskListItemClicked(addTask(recognizedSpeech)) + lifecycleScope.launch { + val match: List? = data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) + if (match != null && match.isNotEmpty() && match[0].isNotEmpty()) { + var recognizedSpeech = match[0] + recognizedSpeech = (recognizedSpeech.substring(0, 1).toUpperCase() + + recognizedSpeech.substring(1).toLowerCase()) + onTaskListItemClicked(addTask(recognizedSpeech)) + } } } REQUEST_MOVE_TASKS -> if (resultCode == Activity.RESULT_OK) { @@ -560,7 +564,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL return onOptionsItemSelected(item) } - fun onTaskListItemClicked(task: Task?) { + fun onTaskListItemClicked(task: Task?) = lifecycleScope.launch { callbacks.onTaskListItemClicked(task) } @@ -712,7 +716,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL } interface TaskListFragmentCallbackHandler { - fun onTaskListItemClicked(task: Task?) + suspend fun onTaskListItemClicked(task: Task?) fun onNavigationIconClicked() } diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt b/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt index 9629e15ff..735349ffa 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt +++ b/app/src/main/java/com/todoroo/astrid/service/TaskCreator.kt @@ -5,7 +5,7 @@ import com.todoroo.astrid.api.CaldavFilter import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.GtasksFilter import com.todoroo.astrid.api.PermaSql -import com.todoroo.astrid.dao.TaskDaoBlocking +import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task.Companion.createDueDate import com.todoroo.astrid.gcal.GCalHelper @@ -23,14 +23,15 @@ import javax.inject.Inject class TaskCreator @Inject constructor( private val gcalHelper: GCalHelper, private val preferences: Preferences, - private val tagDataDao: TagDataDaoBlocking, - private val taskDao: TaskDaoBlocking, - private val tagDao: TagDaoBlocking, - private val googleTaskDao: GoogleTaskDaoBlocking, + private val tagDataDao: TagDataDao, + private val taskDao: TaskDao, + private val tagDao: TagDao, + private val googleTaskDao: GoogleTaskDao, private val defaultFilterProvider: DefaultFilterProvider, - private val caldavDao: CaldavDaoBlocking, - private val locationDao: LocationDaoBlocking) { - fun basicQuickAddTask(title: String): Task { + private val caldavDao: CaldavDao, + private val locationDao: LocationDao) { + + suspend fun basicQuickAddTask(title: String): Task { var title = title title = title.trim { it <= ' ' } val task = createWithValues(title) @@ -51,7 +52,7 @@ class TaskCreator @Inject constructor( caldavDao.insert( task, CaldavTask(task.id, task.getTransitory(CaldavTask.KEY)), addToTop) } else { - val remoteList = defaultFilterProvider.defaultList + val remoteList = defaultFilterProvider.getDefaultList() if (remoteList is GtasksFilter) { googleTaskDao.insertAndShift( GoogleTask(task.id, remoteList.remoteId), addToTop) @@ -70,11 +71,11 @@ class TaskCreator @Inject constructor( return task } - fun createWithValues(title: String?): Task { + suspend fun createWithValues(title: String?): Task { return create(null, title) } - fun createWithValues(filter: Filter?, title: String?): Task { + suspend fun createWithValues(filter: Filter?, title: String?): Task { return create(filter?.valuesForNewTasks, title) } @@ -82,7 +83,7 @@ class TaskCreator @Inject constructor( * Create task from the given content values, saving it. This version doesn't need to start with a * base task model. */ - private fun create(values: Map?, title: String?): Task { + private suspend fun create(values: Map?, title: String?): Task { val task = Task() task.creationDate = DateUtilities.now() task.modificationDate = DateUtilities.now() @@ -128,7 +129,7 @@ class TaskCreator @Inject constructor( return task } - fun createTags(task: Task) { + suspend fun createTags(task: Task) { for (tag in task.tags) { var tagData = tagDataDao.getTagByName(tag) if (tagData == null) { diff --git a/app/src/main/java/com/todoroo/astrid/utility/TitleParser.kt b/app/src/main/java/com/todoroo/astrid/utility/TitleParser.kt index fadde08fa..ade4d3c03 100644 --- a/app/src/main/java/com/todoroo/astrid/utility/TitleParser.kt +++ b/app/src/main/java/com/todoroo/astrid/utility/TitleParser.kt @@ -12,14 +12,14 @@ import com.mdimension.jchronic.Chronic import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task.Companion.createDueDate import org.tasks.Strings.isNullOrEmpty -import org.tasks.data.TagDataDaoBlocking +import org.tasks.data.TagDataDao import timber.log.Timber import java.util.* import java.util.regex.Matcher import java.util.regex.Pattern object TitleParser { - fun parse(tagDataDao: TagDataDaoBlocking, task: Task, tags: ArrayList) { + suspend fun parse(tagDataDao: TagDataDao, task: Task, tags: ArrayList) { repeatHelper(task) listHelper( tagDataDao, @@ -39,7 +39,7 @@ object TitleParser { } else pattern } - fun listHelper(tagDataDao: TagDataDaoBlocking, task: Task, tags: ArrayList) { + suspend fun listHelper(tagDataDao: TagDataDao, task: Task, tags: ArrayList) { var inputText = task.title val tagPattern = Pattern.compile("(\\s|^)#(\\(.*\\)|[^\\s]+)") val contextPattern = Pattern.compile("(\\s|^)@(\\(.*\\)|[^\\s]+)") diff --git a/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt b/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt index 40277c151..007d2e575 100644 --- a/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt +++ b/app/src/main/java/org/tasks/ui/SubtaskControlSet.kt @@ -118,14 +118,16 @@ class SubtaskControlSet : TaskEditControlFragment(), SubtaskViewHolder.Callbacks fun addSubtask() { if (isGoogleTaskChild) { toaster.longToast(R.string.subtasks_multilevel_google_task) - return + } else { + lifecycleScope.launch { + val task = taskCreator.createWithValues("") + viewModel.newSubtasks.add(task) + val editText = addSubtask(task) + editText.requestFocus() + val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT) + } } - val task = taskCreator.createWithValues("") - viewModel.newSubtasks.add(task) - val editText = addSubtask(task) - editText.requestFocus() - val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT) } private fun addSubtask(task: Task): EditText {