mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
449 lines
17 KiB
Kotlin
449 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 com.todoroo.andlib.utility.AndroidUtilities
|
|
import com.todoroo.astrid.activity.TaskEditFragment.TaskEditFragmentCallbackHandler
|
|
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
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import io.reactivex.Single
|
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
import io.reactivex.disposables.CompositeDisposable
|
|
import io.reactivex.schedulers.Schedulers
|
|
import org.tasks.BuildConfig
|
|
import org.tasks.LocalBroadcastManager
|
|
import org.tasks.R
|
|
import org.tasks.activities.TagSettingsActivity
|
|
import org.tasks.billing.Inventory
|
|
import org.tasks.data.Place
|
|
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
|
|
|
|
@AndroidEntryPoint
|
|
class MainActivity : InjectingAppCompatActivity(), TaskListFragmentCallbackHandler, OnListChanged, TimerControlSetCallback, DueDateChangeListener, TaskEditFragmentCallbackHandler, 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
|
|
private var disposables: CompositeDisposable? = null
|
|
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)
|
|
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)) {
|
|
tef.save()
|
|
}
|
|
if (loadFilter || !openFilter && filter == null) {
|
|
disposables!!.add(
|
|
Single.fromCallable {
|
|
val filter = intent.getStringExtra(LOAD_FILTER)
|
|
intent.removeExtra(LOAD_FILTER)
|
|
if (filter.isNullOrBlank()) {
|
|
defaultFilterProvider.startupFilter
|
|
} else {
|
|
defaultFilterProvider.getFilterFromPreference(filter)
|
|
}
|
|
}
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe { filter: Filter? ->
|
|
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()
|
|
val fragmentManager = supportFragmentManager
|
|
fragmentManager
|
|
.beginTransaction()
|
|
.replace(R.id.master, taskListFragment, FRAG_TAG_TASK_LIST)
|
|
.commit()
|
|
fragmentManager.executePendingTransactions()
|
|
}
|
|
|
|
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)
|
|
check(!(BuildConfig.DEBUG && disposables != null && !disposables!!.isDisposed))
|
|
disposables = CompositeDisposable(playServices.check(this))
|
|
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)
|
|
disposables?.dispose()
|
|
}
|
|
|
|
override fun onTaskListItemClicked(task: Task?) {
|
|
AndroidUtilities.assertMainThread()
|
|
if (task == null) {
|
|
return
|
|
}
|
|
val taskEditFragment = taskEditFragment
|
|
taskEditFragment?.save()
|
|
clearUi()
|
|
if (task.isNew) {
|
|
openTask(task)
|
|
} else {
|
|
disposables!!.add(
|
|
Single.fromCallable { taskDao.fetch(task.id) }
|
|
.subscribeOn(Schedulers.io())
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
.subscribe { t: Task? -> this.openTask(t) })
|
|
}
|
|
}
|
|
|
|
private fun openTask(task: Task?) {
|
|
supportFragmentManager
|
|
.beginTransaction()
|
|
.replace(
|
|
R.id.detail,
|
|
TaskEditFragment.newTaskEditFragment(task, filterColor),
|
|
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
|
|
}
|
|
val taskEditFragment = taskEditFragment
|
|
if (taskEditFragment != null) {
|
|
if (preferences.backButtonSavesTask()) {
|
|
taskEditFragment.save()
|
|
} else {
|
|
taskEditFragment.discardButtonClick()
|
|
}
|
|
return
|
|
}
|
|
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)
|
|
|
|
override 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(dateTime: Long) {
|
|
taskEditFragment!!.onDueDateChanged(dateTime)
|
|
}
|
|
|
|
override fun onListChanged(filter: Filter?) {
|
|
taskEditFragment!!.onRemoteListChanged(filter)
|
|
}
|
|
|
|
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"
|
|
}
|
|
} |