Use coroutines in filter provider

pull/1047/head
Alex Baker 4 years ago
parent 2c57d06980
commit 85e8cb49cc

@ -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)));
}
}

@ -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"
}
}

@ -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<FilterListItem>? -> filterAdapter.setData(items!!, selected) })
lifecycleScope.launch {
val items = filterProvider.listPickerItems()
filterAdapter.setData(items, selected)
}
}
companion object {

@ -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) {

@ -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<FilterListItem>
get() = googleTaskFilters(false).plus(caldavFilters(false))
suspend fun listPickerItems(): List<FilterListItem> =
googleTaskFilters(false).plus(caldavFilters(false))
val navDrawerItems: List<FilterListItem>
get() = getAllFilters().plus(navDrawerFooter)
suspend fun navDrawerItems(): List<FilterListItem> =
getAllFilters().plus(navDrawerFooter)
val filterPickerItems: List<FilterListItem>
get() = getAllFilters(showCreate = false)
suspend fun filterPickerItems(): List<FilterListItem> =
getAllFilters(showCreate = false)
val drawerCustomizationItems: List<FilterListItem>
get() = getAllFilters(showBuiltIn = false)
suspend fun drawerCustomizationItems(): List<FilterListItem> =
getAllFilters(showBuiltIn = false)
private fun addFilters(showCreate: Boolean, showBuiltIn: Boolean): List<FilterListItem> =
private suspend fun addFilters(showCreate: Boolean, showBuiltIn: Boolean): List<FilterListItem> =
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<FilterListItem> =
private suspend fun addTags(showCreate: Boolean): List<FilterListItem> =
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<FilterListItem> =
private suspend fun addPlaces(showCreate: Boolean): List<FilterListItem> =
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<FilterListItem> =
private suspend fun getAllFilters(showCreate: Boolean = true, showBuiltIn: Boolean = true): List<FilterListItem> =
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<FilterListItem> {
assertNotMainThread()
private suspend fun googleTaskFilters(showCreate: Boolean = true): List<FilterListItem> {
return googleTaskListDao.getAccounts().flatMap { googleTaskFilter(it, showCreate) }
}
private fun googleTaskFilter(account: GoogleTaskAccount, showCreate: Boolean): List<FilterListItem> =
private suspend fun googleTaskFilter(account: GoogleTaskAccount, showCreate: Boolean): List<FilterListItem> =
listOf(
NavigationDrawerSubheader(
account.account,
@ -201,13 +199,13 @@ class FilterProvider @Inject constructor(
NavigationDrawerFragment.REQUEST_NEW_LIST)
}
private fun caldavFilters(showCreate: Boolean = true): List<FilterListItem> =
private suspend fun caldavFilters(showCreate: Boolean = true): List<FilterListItem> =
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<FilterListItem> =
private suspend fun caldavFilter(account: CaldavAccount, showCreate: Boolean): List<FilterListItem> =
listOf(
NavigationDrawerSubheader(
if (account.accountType == TYPE_LOCAL) {

@ -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<FilterListItem> -> refreshFilterCount(items) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(adapter::submitList)
private fun refreshFilterCount(items: List<FilterListItem>): List<FilterListItem> {
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()
}
}
}

Loading…
Cancel
Save