From 85e8cb49cce46822e34bc7b6a7771084437ac3df Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Fri, 3 Jul 2020 14:00:27 -0500 Subject: [PATCH] Use coroutines in filter provider --- .../activities/FilterSelectionActivity.java | 129 ------------------ .../activities/FilterSelectionActivity.kt | 107 +++++++++++++++ .../java/org/tasks/activities/ListPicker.kt | 18 +-- .../NavigationDrawerCustomization.kt | 33 ++--- .../java/org/tasks/filters/FilterProvider.kt | 44 +++--- .../org/tasks/ui/NavigationDrawerFragment.kt | 50 ++----- 6 files changed, 157 insertions(+), 224 deletions(-) delete mode 100644 app/src/main/java/org/tasks/activities/FilterSelectionActivity.java create mode 100644 app/src/main/java/org/tasks/activities/FilterSelectionActivity.kt diff --git a/app/src/main/java/org/tasks/activities/FilterSelectionActivity.java b/app/src/main/java/org/tasks/activities/FilterSelectionActivity.java deleted file mode 100644 index c3c519a86..000000000 --- a/app/src/main/java/org/tasks/activities/FilterSelectionActivity.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.tasks.activities; - -import android.appwidget.AppWidgetManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import com.todoroo.andlib.utility.AndroidUtilities; -import com.todoroo.astrid.adapter.FilterAdapter; -import com.todoroo.astrid.api.Filter; -import dagger.hilt.android.AndroidEntryPoint; -import dagger.hilt.android.qualifiers.ApplicationContext; -import io.reactivex.Single; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; -import io.reactivex.schedulers.Schedulers; -import javax.inject.Inject; -import org.tasks.LocalBroadcastManager; -import org.tasks.dialogs.DialogBuilder; -import org.tasks.filters.FilterProvider; -import org.tasks.injection.InjectingAppCompatActivity; -import org.tasks.preferences.DefaultFilterProvider; -import org.tasks.preferences.Preferences; -import org.tasks.widget.WidgetPreferences; - -@AndroidEntryPoint -public class FilterSelectionActivity extends InjectingAppCompatActivity { - - public static final String EXTRA_RETURN_FILTER = "extra_include_filter"; - public static final String EXTRA_FILTER = "extra_filter"; - private static final String EXTRA_FILTER_NAME = "extra_filter_name"; - private static final String EXTRA_FILTER_SQL = "extra_filter_query"; - private static final String EXTRA_FILTER_VALUES = "extra_filter_values"; - - @Inject @ApplicationContext Context context; - @Inject DialogBuilder dialogBuilder; - @Inject FilterAdapter filterAdapter; - @Inject FilterProvider filterProvider; - @Inject LocalBroadcastManager localBroadcastManager; - @Inject Preferences preferences; - @Inject DefaultFilterProvider defaultFilterProvider; - - private CompositeDisposable disposables; - private Filter selected; - private final BroadcastReceiver refreshReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - refresh(); - } - }; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent intent = getIntent(); - boolean returnFilter = intent.getBooleanExtra(EXTRA_RETURN_FILTER, false); - int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - selected = intent.getParcelableExtra(EXTRA_FILTER); - - if (savedInstanceState != null) { - filterAdapter.restore(savedInstanceState); - } - - dialogBuilder - .newDialog() - .setSingleChoiceItems( - filterAdapter, - -1, - (dialog, which) -> { - final Filter selectedFilter = (Filter) filterAdapter.getItem(which); - Intent data = new Intent(); - if (returnFilter) { - data.putExtra(EXTRA_FILTER, selectedFilter); - } - if (widgetId != -1) { - new WidgetPreferences(context, preferences, widgetId) - .setFilter(defaultFilterProvider.getFilterPreferenceValue(selectedFilter)); - localBroadcastManager.reconfigureWidget(widgetId); - } - data.putExtra(EXTRA_FILTER_NAME, selectedFilter.listingTitle); - data.putExtra(EXTRA_FILTER_SQL, selectedFilter.getSqlQuery()); - if (selectedFilter.valuesForNewTasks != null) { - data.putExtra( - EXTRA_FILTER_VALUES, - AndroidUtilities.mapToSerializedString(selectedFilter.valuesForNewTasks)); - } - setResult(RESULT_OK, data); - dialog.dismiss(); - }) - .setOnDismissListener(dialog -> finish()) - .show(); - } - - @Override - protected void onResume() { - super.onResume(); - - disposables = new CompositeDisposable(); - - localBroadcastManager.registerRefreshListReceiver(refreshReceiver); - - refresh(); - } - - @Override - protected void onPause() { - super.onPause(); - - localBroadcastManager.unregisterReceiver(refreshReceiver); - - disposables.dispose(); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - filterAdapter.save(outState); - } - - private void refresh() { - disposables.add( - Single.fromCallable(() -> filterProvider.getFilterPickerItems()) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(items -> filterAdapter.setData(items, selected))); - } -} diff --git a/app/src/main/java/org/tasks/activities/FilterSelectionActivity.kt b/app/src/main/java/org/tasks/activities/FilterSelectionActivity.kt new file mode 100644 index 000000000..12de1b5ae --- /dev/null +++ b/app/src/main/java/org/tasks/activities/FilterSelectionActivity.kt @@ -0,0 +1,107 @@ +package org.tasks.activities + +import android.app.Activity +import android.appwidget.AppWidgetManager +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.lifecycle.lifecycleScope +import com.todoroo.andlib.utility.AndroidUtilities +import com.todoroo.astrid.adapter.FilterAdapter +import com.todoroo.astrid.api.Filter +import dagger.hilt.android.AndroidEntryPoint +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.launch +import org.tasks.LocalBroadcastManager +import org.tasks.dialogs.DialogBuilder +import org.tasks.filters.FilterProvider +import org.tasks.injection.InjectingAppCompatActivity +import org.tasks.preferences.DefaultFilterProvider +import org.tasks.preferences.Preferences +import org.tasks.widget.WidgetPreferences +import javax.inject.Inject + +@AndroidEntryPoint +class FilterSelectionActivity : InjectingAppCompatActivity() { + @Inject @ApplicationContext lateinit var context: Context + @Inject lateinit var dialogBuilder: DialogBuilder + @Inject lateinit var filterAdapter: FilterAdapter + @Inject lateinit var filterProvider: FilterProvider + @Inject lateinit var localBroadcastManager: LocalBroadcastManager + @Inject lateinit var preferences: Preferences + @Inject lateinit var defaultFilterProvider: DefaultFilterProvider + + private var selected: Filter? = null + + private val refreshReceiver: BroadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + refresh() + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val intent = intent + val returnFilter = intent.getBooleanExtra(EXTRA_RETURN_FILTER, false) + val widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) + selected = intent.getParcelableExtra(EXTRA_FILTER) + if (savedInstanceState != null) { + filterAdapter.restore(savedInstanceState) + } + dialogBuilder + .newDialog() + .setSingleChoiceItems(filterAdapter, -1) { dialog, which -> + val selectedFilter = filterAdapter.getItem(which) as Filter + val data = Intent() + if (returnFilter) { + data.putExtra(EXTRA_FILTER, selectedFilter) + } + if (widgetId != -1) { + WidgetPreferences(context, preferences, widgetId) + .setFilter(defaultFilterProvider.getFilterPreferenceValue(selectedFilter)) + localBroadcastManager.reconfigureWidget(widgetId) + } + data.putExtra(EXTRA_FILTER_NAME, selectedFilter.listingTitle) + data.putExtra(EXTRA_FILTER_SQL, selectedFilter.getSqlQuery()) + if (selectedFilter.valuesForNewTasks != null) { + data.putExtra( + EXTRA_FILTER_VALUES, + AndroidUtilities.mapToSerializedString(selectedFilter.valuesForNewTasks)) + } + setResult(Activity.RESULT_OK, data) + dialog.dismiss() + } + .setOnDismissListener { finish() } + .show() + } + + override fun onResume() { + super.onResume() + localBroadcastManager.registerRefreshListReceiver(refreshReceiver) + refresh() + } + + override fun onPause() { + super.onPause() + localBroadcastManager.unregisterReceiver(refreshReceiver) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + filterAdapter.save(outState) + } + + private fun refresh() = lifecycleScope.launch { + val items = filterProvider.filterPickerItems() + filterAdapter.setData(items, selected) + } + + companion object { + const val EXTRA_RETURN_FILTER = "extra_include_filter" + const val EXTRA_FILTER = "extra_filter" + private const val EXTRA_FILTER_NAME = "extra_filter_name" + private const val EXTRA_FILTER_SQL = "extra_filter_query" + private const val EXTRA_FILTER_VALUES = "extra_filter_values" + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/activities/ListPicker.kt b/app/src/main/java/org/tasks/activities/ListPicker.kt index 3c5e2e98c..576985b21 100644 --- a/app/src/main/java/org/tasks/activities/ListPicker.kt +++ b/app/src/main/java/org/tasks/activities/ListPicker.kt @@ -10,16 +10,13 @@ import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import com.todoroo.astrid.adapter.FilterAdapter import com.todoroo.astrid.api.CaldavFilter import com.todoroo.astrid.api.Filter -import com.todoroo.astrid.api.FilterListItem import com.todoroo.astrid.api.GtasksFilter 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 kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.dialogs.DialogBuilder import org.tasks.filters.FilterProvider @@ -32,7 +29,6 @@ class ListPicker : DialogFragment() { @Inject lateinit var filterProvider: FilterProvider @Inject lateinit var localBroadcastManager: LocalBroadcastManager - private var disposables: CompositeDisposable? = null private val refreshReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { refresh() @@ -48,7 +44,6 @@ class ListPicker : DialogFragment() { override fun onResume() { super.onResume() - disposables = CompositeDisposable() localBroadcastManager.registerRefreshListReceiver(refreshReceiver) refresh() } @@ -56,7 +51,6 @@ class ListPicker : DialogFragment() { override fun onPause() { super.onPause() localBroadcastManager.unregisterReceiver(refreshReceiver) - disposables!!.dispose() } override fun onSaveInstanceState(outState: Bundle) { @@ -74,10 +68,10 @@ class ListPicker : DialogFragment() { private fun refresh() { val noSelection = requireArguments().getBoolean(EXTRA_NO_SELECTION, false) val selected: Filter? = if (noSelection) null else arguments?.getParcelable(EXTRA_SELECTED_FILTER) - disposables!!.add(Single.fromCallable(filterProvider::listPickerItems) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { items: List? -> filterAdapter.setData(items!!, selected) }) + lifecycleScope.launch { + val items = filterProvider.listPickerItems() + filterAdapter.setData(items, selected) + } } companion object { diff --git a/app/src/main/java/org/tasks/activities/NavigationDrawerCustomization.kt b/app/src/main/java/org/tasks/activities/NavigationDrawerCustomization.kt index 93784eb63..3f9c6599d 100644 --- a/app/src/main/java/org/tasks/activities/NavigationDrawerCustomization.kt +++ b/app/src/main/java/org/tasks/activities/NavigationDrawerCustomization.kt @@ -7,6 +7,7 @@ import android.os.Bundle import android.os.Parcelable import android.view.MenuItem import androidx.appcompat.widget.Toolbar +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper.* import androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags @@ -17,10 +18,7 @@ import com.todoroo.astrid.adapter.NavigationDrawerAdapter import com.todoroo.astrid.api.* import com.todoroo.astrid.api.FilterListItem.Type.ITEM 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 kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.R import org.tasks.caldav.BaseCaldavCalendarSettingsActivity @@ -50,7 +48,6 @@ class NavigationDrawerCustomization : ThemedInjectingAppCompatActivity(), Toolba private lateinit var binding: ActivityTagOrganizerBinding private lateinit var toolbar: Toolbar - private var disposables: CompositeDisposable? = null private val refreshReceiver = RefreshReceiver() override fun onCreate(savedInstanceState: Bundle?) { @@ -83,32 +80,18 @@ class NavigationDrawerCustomization : ThemedInjectingAppCompatActivity(), Toolba localBroadcastManager.unregisterReceiver(refreshReceiver) } - override fun onStart() { - super.onStart() - disposables = CompositeDisposable() - } - - override fun onStop() { - super.onStop() - disposables?.dispose() - } - override fun onResume() { super.onResume() localBroadcastManager.registerRefreshListReceiver(refreshReceiver) updateFilters() } - private fun updateFilters() = - disposables?.add( - Single.fromCallable { - filterProvider.drawerCustomizationItems.apply { - forEach { f -> f.count = 0 } - } - } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(adapter::submitList)) + private fun updateFilters() = lifecycleScope.launch { + filterProvider + .drawerCustomizationItems() + .onEach { f -> f.count = 0 } + .apply(adapter::submitList) + } private fun onClick(item: FilterListItem?) { if (item is NavigationDrawerAction) { diff --git a/app/src/main/java/org/tasks/filters/FilterProvider.kt b/app/src/main/java/org/tasks/filters/FilterProvider.kt index 04d5efb98..37ae41991 100644 --- a/app/src/main/java/org/tasks/filters/FilterProvider.kt +++ b/app/src/main/java/org/tasks/filters/FilterProvider.kt @@ -2,7 +2,6 @@ package org.tasks.filters import android.content.Context import android.content.Intent -import com.todoroo.andlib.utility.AndroidUtilities.assertNotMainThread import com.todoroo.astrid.api.CustomFilter import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.FilterListItem @@ -30,26 +29,26 @@ class FilterProvider @Inject constructor( @param:ApplicationContext private val context: Context, private val inventory: Inventory, private val builtInFilterExposer: BuiltInFilterExposer, - private val filterDao: FilterDaoBlocking, - private val tagDataDao: TagDataDaoBlocking, - private val googleTaskListDao: GoogleTaskListDaoBlocking, - private val caldavDao: CaldavDaoBlocking, + private val filterDao: FilterDao, + private val tagDataDao: TagDataDao, + private val googleTaskListDao: GoogleTaskListDao, + private val caldavDao: CaldavDao, private val preferences: Preferences, - private val locationDao: LocationDaoBlocking) { + private val locationDao: LocationDao) { - val listPickerItems: List - get() = googleTaskFilters(false).plus(caldavFilters(false)) + suspend fun listPickerItems(): List = + googleTaskFilters(false).plus(caldavFilters(false)) - val navDrawerItems: List - get() = getAllFilters().plus(navDrawerFooter) + suspend fun navDrawerItems(): List = + getAllFilters().plus(navDrawerFooter) - val filterPickerItems: List - get() = getAllFilters(showCreate = false) + suspend fun filterPickerItems(): List = + getAllFilters(showCreate = false) - val drawerCustomizationItems: List - get() = getAllFilters(showBuiltIn = false) + suspend fun drawerCustomizationItems(): List = + getAllFilters(showBuiltIn = false) - private fun addFilters(showCreate: Boolean, showBuiltIn: Boolean): List = + private suspend fun addFilters(showCreate: Boolean, showBuiltIn: Boolean): List = if (!preferences.getBoolean(R.string.p_filters_enabled, true)) { emptyList() } else { @@ -74,7 +73,7 @@ class FilterProvider @Inject constructor( } } - private fun addTags(showCreate: Boolean): List = + private suspend fun addTags(showCreate: Boolean): List = if (!preferences.getBoolean(R.string.p_tags_enabled, true)) { emptyList() } else { @@ -102,7 +101,7 @@ class FilterProvider @Inject constructor( } } - private fun addPlaces(showCreate: Boolean): List = + private suspend fun addPlaces(showCreate: Boolean): List = if (!preferences.getBoolean(R.string.p_places_enabled, true)) { emptyList() } else { @@ -130,7 +129,7 @@ class FilterProvider @Inject constructor( } } - private fun getAllFilters(showCreate: Boolean = true, showBuiltIn: Boolean = true): List = + private suspend fun getAllFilters(showCreate: Boolean = true, showBuiltIn: Boolean = true): List = if (showBuiltIn) { arrayListOf(builtInFilterExposer.myTasksFilter) } else { @@ -174,12 +173,11 @@ class FilterProvider @Inject constructor( Intent(context, HelpAndFeedback::class.java), 0)) - private fun googleTaskFilters(showCreate: Boolean = true): List { - assertNotMainThread() + private suspend fun googleTaskFilters(showCreate: Boolean = true): List { return googleTaskListDao.getAccounts().flatMap { googleTaskFilter(it, showCreate) } } - private fun googleTaskFilter(account: GoogleTaskAccount, showCreate: Boolean): List = + private suspend fun googleTaskFilter(account: GoogleTaskAccount, showCreate: Boolean): List = listOf( NavigationDrawerSubheader( account.account, @@ -201,13 +199,13 @@ class FilterProvider @Inject constructor( NavigationDrawerFragment.REQUEST_NEW_LIST) } - private fun caldavFilters(showCreate: Boolean = true): List = + private suspend fun caldavFilters(showCreate: Boolean = true): List = caldavDao.getAccounts() .ifEmpty { listOf(caldavDao.setupLocalAccount(context)) } .filter { it.accountType != TYPE_LOCAL || preferences.getBoolean(R.string.p_lists_enabled, true) } .flatMap { caldavFilter(it, showCreate) } - private fun caldavFilter(account: CaldavAccount, showCreate: Boolean): List = + private suspend fun caldavFilter(account: CaldavAccount, showCreate: Boolean): List = listOf( NavigationDrawerSubheader( if (account.accountType == TYPE_LOCAL) { diff --git a/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt b/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt index 0d5d0d6e4..7d812a343 100644 --- a/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt +++ b/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.kt @@ -14,18 +14,15 @@ import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout.SimpleDrawerListener import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.todoroo.andlib.utility.AndroidUtilities import com.todoroo.astrid.adapter.NavigationDrawerAdapter import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.FilterListItem -import com.todoroo.astrid.dao.TaskDaoBlocking +import com.todoroo.astrid.dao.TaskDao 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 kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager import org.tasks.R import org.tasks.billing.PurchaseActivity @@ -42,11 +39,10 @@ class NavigationDrawerFragment : Fragment() { @Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var adapter: NavigationDrawerAdapter @Inject lateinit var filterProvider: FilterProvider - @Inject lateinit var taskDao: TaskDaoBlocking + @Inject lateinit var taskDao: TaskDao private lateinit var recyclerView: RecyclerView private lateinit var mDrawerLayout: DrawerLayout - private var disposables: CompositeDisposable? = null private var mFragmentContainerView: View? = null override fun onCreate(savedInstanceState: Bundle?) { @@ -120,16 +116,6 @@ class NavigationDrawerFragment : Fragment() { localBroadcastManager.unregisterReceiver(refreshReceiver) } - override fun onStart() { - super.onStart() - disposables = CompositeDisposable() - } - - override fun onStop() { - super.onStop() - disposables?.dispose() - } - override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) adapter.save(outState) @@ -147,24 +133,18 @@ class NavigationDrawerFragment : Fragment() { override fun onResume() { super.onResume() localBroadcastManager.registerRefreshListReceiver(refreshReceiver) - disposables?.add(updateFilters()) + updateFilters() } - private fun updateFilters() = - Single.fromCallable { filterProvider.navDrawerItems } - .map { items: List -> refreshFilterCount(items) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(adapter::submitList) - - private fun refreshFilterCount(items: List): List { - AndroidUtilities.assertNotMainThread() - for (item in items) { - if (item is Filter && item.count == -1) { - item.count = taskDao.count(item) - } - } - return items + private fun updateFilters() = lifecycleScope.launch { + filterProvider + .navDrawerItems() + .onEach { + if (it is Filter && it.count == -1) { + it.count = taskDao.count(it) + } + } + .apply(adapter::submitList) } private inner class RefreshReceiver : BroadcastReceiver() { @@ -174,7 +154,7 @@ class NavigationDrawerFragment : Fragment() { } val action = intent.action if (LocalBroadcastManager.REFRESH == action || LocalBroadcastManager.REFRESH_LIST == action) { - disposables?.add(updateFilters()) + updateFilters() } } }