You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt

452 lines
17 KiB
Kotlin

/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.view.ActionMode
import androidx.drawerlayout.widget.DrawerLayout.SimpleDrawerListener
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.astrid.activity.TaskEditFragment.Companion.newTaskEditFragment
import com.todoroo.astrid.activity.TaskListFragment.TaskListFragmentCallbackHandler
import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task
import com.todoroo.astrid.service.TaskCreator
import com.todoroo.astrid.timers.TimerControlSet.TimerControlSetCallback
4 years ago
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.tasks.LocalBroadcastManager
import org.tasks.R
import org.tasks.activities.TagSettingsActivity
import org.tasks.billing.Inventory
import org.tasks.data.AlarmDao
import org.tasks.data.LocationDao
import org.tasks.data.Place
import org.tasks.data.TagDataDao
import org.tasks.databinding.TaskListActivityBinding
import org.tasks.dialogs.SortDialog.SortDialogCallback
import org.tasks.dialogs.WhatsNewDialog
import org.tasks.filters.PlaceFilter
import org.tasks.fragments.CommentBarFragment.CommentBarFragmentCallback
import org.tasks.gtasks.PlayServices
import org.tasks.injection.InjectingAppCompatActivity
import org.tasks.intents.TaskIntents
import org.tasks.location.LocationPickerActivity
import org.tasks.preferences.DefaultFilterProvider
import org.tasks.preferences.Preferences
import org.tasks.receivers.RepeatConfirmationReceiver
import org.tasks.tasklist.ActionUtils
import org.tasks.themes.ColorProvider
import org.tasks.themes.Theme
import org.tasks.themes.ThemeColor
import org.tasks.ui.DeadlineControlSet.DueDateChangeListener
import org.tasks.ui.EmptyTaskEditFragment.Companion.newEmptyTaskEditFragment
import org.tasks.ui.ListFragment.OnListChanged
import org.tasks.ui.NavigationDrawerFragment
import javax.inject.Inject
4 years ago
@AndroidEntryPoint
class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandler, OnListChanged, TimerControlSetCallback, DueDateChangeListener, CommentBarFragmentCallback, SortDialogCallback {
@Inject lateinit var preferences: Preferences
@Inject lateinit var repeatConfirmationReceiver: RepeatConfirmationReceiver
@Inject lateinit var defaultFilterProvider: DefaultFilterProvider
@Inject lateinit var theme: Theme
@Inject lateinit var taskDao: TaskDao
@Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var taskCreator: TaskCreator
@Inject lateinit var playServices: PlayServices
@Inject lateinit var inventory: Inventory
@Inject lateinit var colorProvider: ColorProvider
@Inject lateinit var locationDao: LocationDao
@Inject lateinit var tagDataDao: TagDataDao
@Inject lateinit var alarmDao: AlarmDao
private lateinit var navigationDrawer: NavigationDrawerFragment
private var currentNightMode = 0
private var currentPro = false
private var filter: Filter? = null
private var actionMode: ActionMode? = null
private lateinit var binding: TaskListActivityBinding
/** @see android.app.Activity.onCreate
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
4 years ago
theme.applyTheme(this)
currentNightMode = nightMode
currentPro = inventory.hasPro()
binding = TaskListActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
if (savedInstanceState != null) {
filter = savedInstanceState.getParcelable(EXTRA_FILTER)
applyTheme()
}
navigationDrawer = navigationDrawerFragment
navigationDrawer.setUp(binding.drawerLayout)
binding.drawerLayout.addDrawerListener(
object : SimpleDrawerListener() {
override fun onDrawerStateChanged(newState: Int) {
finishActionMode()
}
})
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == NavigationDrawerFragment.REQUEST_SETTINGS) {
if (AndroidUtilities.atLeastNougat()) {
recreate()
} else {
finish()
startActivity(TaskIntents.getTaskListIntent(this, filter))
}
} else if (requestCode == NavigationDrawerFragment.REQUEST_NEW_LIST) {
if (resultCode == Activity.RESULT_OK && data != null) {
val filter: Filter? = data.getParcelableExtra(OPEN_FILTER)
if (filter != null) {
startActivity(TaskIntents.getTaskListIntent(this, filter))
}
}
} else if (requestCode == NavigationDrawerFragment.REQUEST_NEW_PLACE) {
if (resultCode == Activity.RESULT_OK && data != null) {
val place: Place? = data.getParcelableExtra(LocationPickerActivity.EXTRA_PLACE)
if (place != null) {
startActivity(TaskIntents.getTaskListIntent(this, PlaceFilter(place)))
}
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putParcelable(EXTRA_FILTER, filter)
}
private fun clearUi() {
finishActionMode()
navigationDrawer.closeDrawer()
}
private fun getTaskToLoad(filter: Filter?): Task? {
val intent = intent
if (intent.hasExtra(CREATE_TASK)) {
intent.removeExtra(CREATE_TASK)
return taskCreator.createWithValues(filter, "")
}
if (intent.hasExtra(OPEN_TASK)) {
val task: Task? = intent.getParcelableExtra(OPEN_TASK)
intent.removeExtra(OPEN_TASK)
return task
}
return null
}
private fun openTask(filter: Filter?) {
val task = getTaskToLoad(filter)
when {
task != null -> onTaskListItemClicked(task)
taskEditFragment == null -> hideDetailFragment()
else -> showDetailFragment()
}
}
private fun handleIntent() {
val intent = intent
val openFilter = intent.hasExtra(OPEN_FILTER)
val loadFilter = intent.hasExtra(LOAD_FILTER)
val tef = taskEditFragment
if (tef != null && (openFilter || loadFilter)) {
lifecycleScope.launch(NonCancellable) {
tef.save()
}
}
if (loadFilter || !openFilter && filter == null) {
lifecycleScope.launch {
val filterString = intent.getStringExtra(LOAD_FILTER)
intent.removeExtra(LOAD_FILTER)
val filter = if (filterString.isNullOrBlank()) {
defaultFilterProvider.getStartupFilter()
} else {
defaultFilterProvider.getFilterFromPreference(filterString)
}
clearUi()
openTaskListFragment(filter)
openTask(filter)
}
} else if (openFilter) {
val filter: Filter? = intent.getParcelableExtra(OPEN_FILTER)
intent.removeExtra(OPEN_FILTER)
clearUi()
openTaskListFragment(filter)
openTask(filter)
} else {
val existing = taskListFragment
openTaskListFragment(
if (existing == null || existing.getFilter() !== filter) TaskListFragment.newTaskListFragment(applicationContext, filter) else existing,
false)
openTask(filter)
}
if (intent.hasExtra(TOKEN_CREATE_NEW_LIST_NAME)) {
val listName = intent.getStringExtra(TOKEN_CREATE_NEW_LIST_NAME)
intent.removeExtra(TOKEN_CREATE_NEW_LIST_NAME)
val activityIntent = Intent(this@MainActivity, TagSettingsActivity::class.java)
activityIntent.putExtra(TagSettingsActivity.TOKEN_AUTOPOPULATE_NAME, listName)
startActivityForResult(activityIntent, NavigationDrawerFragment.REQUEST_NEW_LIST)
}
}
private fun showDetailFragment() {
if (isSinglePaneLayout) {
binding.detail.visibility = View.VISIBLE
binding.master.visibility = View.GONE
}
}
private fun hideDetailFragment() {
supportFragmentManager
.beginTransaction()
.replace(R.id.detail, newEmptyTaskEditFragment(filter!!))
.commit()
if (isSinglePaneLayout) {
binding.master.visibility = View.VISIBLE
binding.detail.visibility = View.GONE
}
}
private fun openTaskListFragment(filter: Filter?, force: Boolean = false) {
openTaskListFragment(TaskListFragment.newTaskListFragment(applicationContext, filter), force)
}
private fun openTaskListFragment(taskListFragment: TaskListFragment, force: Boolean) {
AndroidUtilities.assertMainThread()
val newFilter = taskListFragment.getFilter()
if (filter != null
&& !force
&& filter!!.areItemsTheSame(newFilter)
&& filter!!.areContentsTheSame(newFilter)) {
return
}
filter = newFilter
navigationDrawer.setSelected(filter)
defaultFilterProvider.lastViewedFilter = newFilter
applyTheme()
supportFragmentManager
.beginTransaction()
.replace(R.id.master, taskListFragment, FRAG_TAG_TASK_LIST)
.commitNow()
}
private fun applyTheme() {
val filterColor = filterColor
filterColor.setStatusBarColor(binding.drawerLayout)
filterColor.applyToNavigationBar(this)
filterColor.applyTaskDescription(this, filter?.listingTitle ?: getString(R.string.app_name))
theme.withThemeColor(filterColor).applyToContext(this)
}
private val filterColor: ThemeColor
get() = if (filter != null && filter!!.tint != 0) colorProvider.getThemeColor(filter!!.tint, true) else theme.themeColor
private val navigationDrawerFragment: NavigationDrawerFragment
get() = supportFragmentManager
.findFragmentById(NavigationDrawerFragment.FRAGMENT_NAVIGATION_DRAWER) as NavigationDrawerFragment
override fun onResume() {
super.onResume()
if (currentNightMode != nightMode || currentPro != inventory.hasPro()) {
recreate()
return
}
localBroadcastManager.registerRepeatReceiver(repeatConfirmationReceiver)
if (preferences.getBoolean(R.string.p_just_updated, false)) {
if (preferences.getBoolean(R.string.p_show_whats_new, true)) {
val fragmentManager = supportFragmentManager
if (fragmentManager.findFragmentByTag(FRAG_TAG_WHATS_NEW) == null) {
WhatsNewDialog().show(fragmentManager, FRAG_TAG_WHATS_NEW)
}
}
preferences.setBoolean(R.string.p_just_updated, false)
}
}
override fun onResumeFragments() {
super.onResumeFragments()
handleIntent()
}
private val nightMode: Int
get() = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
override fun onPause() {
super.onPause()
localBroadcastManager.unregisterReceiver(repeatConfirmationReceiver)
}
override fun onTaskListItemClicked(task: Task?) {
AndroidUtilities.assertMainThread()
if (task == null) {
return
}
lifecycleScope.launch {
taskEditFragment?.let {
it.editViewModel.cleared.removeObservers(this@MainActivity)
withContext(NonCancellable) {
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() {
hideKeyboard()
navigationDrawer.openDrawer()
}
override fun onBackPressed() {
if (navigationDrawer.isDrawerOpen) {
navigationDrawer.closeDrawer()
return
}
taskEditFragment?.let {
if (preferences.backButtonSavesTask()) {
lifecycleScope.launch(NonCancellable) {
it.save()
}
} else {
it.discardButtonClick()
}
return@onBackPressed
}
if (taskListFragment?.collapseSearchView() == true) {
return
}
finish()
}
val taskListFragment: TaskListFragment?
get() = supportFragmentManager.findFragmentByTag(FRAG_TAG_TASK_LIST) as TaskListFragment?
val taskEditFragment: TaskEditFragment?
get() = supportFragmentManager.findFragmentByTag(TaskEditFragment.TAG_TASKEDIT_FRAGMENT) as TaskEditFragment?
override fun stopTimer(): Task {
return taskEditFragment!!.stopTimer()
}
override fun startTimer(): Task {
return taskEditFragment!!.startTimer()
}
private val isSinglePaneLayout: Boolean
get() = !resources.getBoolean(R.bool.two_pane_layout)
fun removeTaskEditFragment() {
supportFragmentManager
.popBackStackImmediate(
TaskEditFragment.TAG_TASKEDIT_FRAGMENT, FragmentManager.POP_BACK_STACK_INCLUSIVE)
hideDetailFragment()
hideKeyboard()
taskListFragment?.loadTaskListContent()
}
private fun hideKeyboard() {
val view = currentFocus
if (view != null) {
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
}
override fun addComment(message: String?, picture: Uri?) {
val taskEditFragment = taskEditFragment
taskEditFragment?.addComment(message, picture)
}
override fun sortChanged(reload: Boolean) {
taskListFragment?.clearCollapsed()
localBroadcastManager.broadcastRefresh()
if (reload) {
openTaskListFragment(filter, true)
}
}
override fun onSupportActionModeStarted(mode: ActionMode) {
super.onSupportActionModeStarted(mode)
actionMode = mode
val filterColor = filterColor
ActionUtils.applySupportActionModeColor(filterColor, mode)
filterColor.setStatusBarColor(this)
}
@SuppressLint("NewApi")
override fun onSupportActionModeFinished(mode: ActionMode) {
super.onSupportActionModeFinished(mode)
window.statusBarColor = 0
}
private fun finishActionMode() {
actionMode?.finish()
actionMode = null
}
override fun dueDateChanged() {
taskEditFragment!!.onDueDateChanged()
}
override fun onListChanged(filter: Filter?) {
taskEditFragment!!.onRemoteListChanged(filter)
}
init {
lifecycleScope.launchWhenResumed {
playServices.check(this@MainActivity)
}
}
companion object {
/** For indicating the new list screen should be launched at fragment setup time */
const val TOKEN_CREATE_NEW_LIST_NAME = "newListName" // $NON-NLS-1$
const val OPEN_FILTER = "open_filter" // $NON-NLS-1$
const val LOAD_FILTER = "load_filter"
const val CREATE_TASK = "open_task" // $NON-NLS-1$
const val OPEN_TASK = "open_new_task" // $NON-NLS-1$
private const val FRAG_TAG_TASK_LIST = "frag_tag_task_list"
private const val FRAG_TAG_WHATS_NEW = "frag_tag_whats_new"
private const val EXTRA_FILTER = "extra_filter"
}
}