From d686b8c7e0649e73c0131845f86a3449a535c69f Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Mon, 25 Mar 2024 00:24:09 -0500 Subject: [PATCH] Add TasksMenu composable --- .../todoroo/astrid/activity/MainActivity.kt | 157 +++--------------- .../tasks/compose/drawer/TaskListDrawer.kt | 12 +- .../org/tasks/compose/drawer/TasksMenu.kt | 133 +++++++++++++++ .../main/java/org/tasks/extensions/Context.kt | 11 ++ 4 files changed, 174 insertions(+), 139 deletions(-) create mode 100644 app/src/main/java/org/tasks/compose/drawer/TasksMenu.kt 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 bc1bb73ca..596fd8081 100644 --- a/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/MainActivity.kt @@ -12,15 +12,9 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.view.ActionMode -import androidx.compose.material.MaterialTheme -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.mandatorySystemGestures import androidx.core.content.IntentCompat.getParcelableExtra import androidx.lifecycle.Lifecycle import androidx.lifecycle.flowWithLifecycle @@ -34,7 +28,6 @@ import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.data.Task import com.todoroo.astrid.service.TaskCreator import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -42,18 +35,10 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.tasks.BuildConfig import org.tasks.R -import org.tasks.Tasks.Companion.IS_GENERIC -import org.tasks.activities.NavigationDrawerCustomization import org.tasks.analytics.Firebase import org.tasks.billing.Inventory -import org.tasks.billing.PurchaseActivity import org.tasks.compose.collectAsStateLifecycleAware -import org.tasks.compose.drawer.DrawerAction -import org.tasks.compose.drawer.DrawerItem -import org.tasks.compose.drawer.ModalBottomSheet -import org.tasks.compose.drawer.SheetState -import org.tasks.compose.drawer.SheetValue -import org.tasks.compose.drawer.TaskListDrawer +import org.tasks.compose.drawer.TasksMenu import org.tasks.data.AlarmDao import org.tasks.data.LocationDao import org.tasks.data.Place @@ -62,14 +47,11 @@ import org.tasks.databinding.TaskListActivityBinding import org.tasks.dialogs.NewFilterDialog import org.tasks.dialogs.WhatsNewDialog import org.tasks.extensions.Context.nightMode -import org.tasks.extensions.Context.openUri import org.tasks.extensions.hideKeyboard import org.tasks.filters.FilterProvider import org.tasks.filters.PlaceFilter import org.tasks.location.LocationPickerActivity.Companion.EXTRA_PLACE import org.tasks.preferences.DefaultFilterProvider -import org.tasks.preferences.HelpAndFeedback -import org.tasks.preferences.MainPreferences import org.tasks.preferences.Preferences import org.tasks.themes.ColorProvider import org.tasks.themes.Theme @@ -107,7 +89,6 @@ class MainActivity : AppCompatActivity() { /** @see android.app.Activity.onCreate */ - @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) theme.applyTheme(this) @@ -122,113 +103,29 @@ class MainActivity : AppCompatActivity() { val state = viewModel.state.collectAsStateLifecycleAware().value if (state.drawerOpen) { MdcTheme { - var expanded by remember { mutableStateOf(false) } - val skipPartiallyExpanded = remember(expanded) { - expanded || preferences.isTopAppBar - } - val sheetState = rememberSaveable( - skipPartiallyExpanded, - saver = SheetState.Saver( - skipPartiallyExpanded = skipPartiallyExpanded, - confirmValueChange = { true }, - ) - ) { - SheetState( - skipPartiallyExpanded = skipPartiallyExpanded, - initialValue = if (skipPartiallyExpanded) SheetValue.Expanded else SheetValue.PartiallyExpanded, - confirmValueChange = { true }, - skipHiddenState = false, - ) - } - LaunchedEffect(sheetState.currentValue) { - if (sheetState.currentValue == SheetValue.Expanded) { - expanded = true - } - } - ModalBottomSheet( - sheetState = sheetState, - containerColor = MaterialTheme.colors.surface, - onDismissRequest = { viewModel.setDrawerOpen(false) } - ) { - val scope = rememberCoroutineScope() - TaskListDrawer( - begForMoney = state.begForMoney, - filters = state.drawerItems, - onClick = { - when (it) { - is DrawerItem.Filter -> { - viewModel.setFilter(it.type()) - scope.launch(Dispatchers.Default) { - sheetState.hide() - viewModel.setDrawerOpen(false) - } - } - is DrawerItem.Header -> { - viewModel.toggleCollapsed(it.type()) - } - } - }, - onAddClick = { - scope.launch(Dispatchers.Default) { - sheetState.hide() - viewModel.setDrawerOpen(false) - val subheaderType = it.type() - val rc = subheaderType.addIntentRc - if (rc == FilterProvider.REQUEST_NEW_FILTER) { - NewFilterDialog.newFilterDialog().show( - supportFragmentManager, - SubheaderClickHandler.FRAG_TAG_NEW_FILTER - ) - } else { - val intent = subheaderType.addIntent ?: return@launch - startActivityForResult(intent, rc) - } - } - }, - onDrawerAction = { - viewModel.setDrawerOpen(false) - when (it) { - DrawerAction.PURCHASE -> - if (IS_GENERIC) - openUri(R.string.url_donate) - else - startActivity( - Intent( - this@MainActivity, - PurchaseActivity::class.java - ) - ) - - DrawerAction.CUSTOMIZE_DRAWER -> - startActivity( - Intent( - this@MainActivity, - NavigationDrawerCustomization::class.java - ) - ) - - DrawerAction.SETTINGS -> - settingsRequest.launch( - Intent( - this@MainActivity, - MainPreferences::class.java - ) - ) - - DrawerAction.HELP_AND_FEEDBACK -> - startActivity( - Intent( - this@MainActivity, - HelpAndFeedback::class.java - ) - ) - } - }, - onErrorClick = { - startActivity(Intent(this@MainActivity, MainPreferences::class.java)) - }, - ) - } + TasksMenu( + bottomPadding = WindowInsets.mandatorySystemGestures + .asPaddingValues() + .calculateBottomPadding(), + items = state.drawerItems, + begForMoney = state.begForMoney, + isTopAppBar = preferences.isTopAppBar, + setFilter = { viewModel.setFilter(it) }, + toggleCollapsed = { viewModel.toggleCollapsed(it) }, + addFilter = { + val rc = it.addIntentRc + if (rc == FilterProvider.REQUEST_NEW_FILTER) { + NewFilterDialog.newFilterDialog().show( + supportFragmentManager, + SubheaderClickHandler.FRAG_TAG_NEW_FILTER + ) + } else { + val intent = it.addIntent ?: return@TasksMenu + startActivityForResult(intent, rc) + } + }, + dismiss = { viewModel.setDrawerOpen(false) }, + ) } } } diff --git a/app/src/main/java/org/tasks/compose/drawer/TaskListDrawer.kt b/app/src/main/java/org/tasks/compose/drawer/TaskListDrawer.kt index 062a402f8..8bf88b2de 100644 --- a/app/src/main/java/org/tasks/compose/drawer/TaskListDrawer.kt +++ b/app/src/main/java/org/tasks/compose/drawer/TaskListDrawer.kt @@ -14,11 +14,8 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.mandatorySystemGestures import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -46,6 +43,7 @@ import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.google.android.material.composethemeadapter.MdcTheme import com.todoroo.astrid.api.FilterImpl @@ -58,6 +56,7 @@ import org.tasks.filters.NavigationDrawerSubheader @Composable fun TaskListDrawer( + bottomPadding: Dp = 0.dp, begForMoney: Boolean, filters: ImmutableList, onClick: (DrawerItem) -> Unit, @@ -65,14 +64,9 @@ fun TaskListDrawer( onAddClick: (DrawerItem.Header) -> Unit, onErrorClick: () -> Unit, ) { - val insets = WindowInsets.mandatorySystemGestures LazyColumn( modifier = Modifier - .padding( - bottom = insets - .asPaddingValues() - .calculateBottomPadding() - ) + .padding(bottom = bottomPadding) .animateContentSize( animationSpec = spring( dampingRatio = Spring.DampingRatioNoBouncy, diff --git a/app/src/main/java/org/tasks/compose/drawer/TasksMenu.kt b/app/src/main/java/org/tasks/compose/drawer/TasksMenu.kt new file mode 100644 index 000000000..13dd517c1 --- /dev/null +++ b/app/src/main/java/org/tasks/compose/drawer/TasksMenu.kt @@ -0,0 +1,133 @@ +package org.tasks.compose.drawer + +import android.content.Intent +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.material.MaterialTheme +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.todoroo.astrid.api.Filter +import kotlinx.collections.immutable.ImmutableList +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import org.tasks.R +import org.tasks.Tasks +import org.tasks.activities.NavigationDrawerCustomization +import org.tasks.billing.PurchaseActivity +import org.tasks.extensions.Context.findActivity +import org.tasks.extensions.Context.openUri +import org.tasks.filters.NavigationDrawerSubheader +import org.tasks.preferences.HelpAndFeedback +import org.tasks.preferences.MainPreferences + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TasksMenu( + bottomPadding: Dp = 0.dp, + items: ImmutableList, + isTopAppBar: Boolean, + begForMoney: Boolean, + setFilter: (Filter) -> Unit, + toggleCollapsed: (NavigationDrawerSubheader) -> Unit, + addFilter: (NavigationDrawerSubheader) -> Unit, + dismiss: () -> Unit, +) { + var expanded by remember { mutableStateOf(false) } + val skipPartiallyExpanded = remember(expanded) { + expanded || isTopAppBar + } + val density = LocalDensity.current + val sheetState = rememberSaveable( + skipPartiallyExpanded, + saver = SheetState.Saver( + skipPartiallyExpanded = skipPartiallyExpanded, + confirmValueChange = { true }, + density = density, + ) + ) { + SheetState( + skipPartiallyExpanded = skipPartiallyExpanded, + initialValue = if (skipPartiallyExpanded) SheetValue.Expanded else SheetValue.PartiallyExpanded, + confirmValueChange = { true }, + skipHiddenState = false, + density = density, + ) + } + LaunchedEffect(sheetState.currentValue) { + if (sheetState.currentValue == SheetValue.Expanded) { + expanded = true + } + } + val context = LocalContext.current + val settingsRequest = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { + context.findActivity()?.recreate() + } + ModalBottomSheet( + sheetState = sheetState, + containerColor = MaterialTheme.colors.surface, + onDismissRequest = { dismiss() } + ) { + val scope = rememberCoroutineScope() + TaskListDrawer( + bottomPadding = bottomPadding, + begForMoney = begForMoney, + filters = items, + onClick = { + when (it) { + is DrawerItem.Filter -> { + setFilter(it.type()) + scope.launch(Dispatchers.Default) { + sheetState.hide() + dismiss() + } + } + is DrawerItem.Header -> { + toggleCollapsed(it.type()) + } + } + }, + onAddClick = { + scope.launch(Dispatchers.Default) { + sheetState.hide() + dismiss() + addFilter(it.type()) + } + }, + onDrawerAction = { + dismiss() + when (it) { + DrawerAction.PURCHASE -> + if (Tasks.IS_GENERIC) + context.openUri(R.string.url_donate) + else + context.startActivity(Intent(context, PurchaseActivity::class.java)) + + DrawerAction.CUSTOMIZE_DRAWER -> + context.startActivity( + Intent(context, NavigationDrawerCustomization::class.java) + ) + + DrawerAction.SETTINGS -> + settingsRequest.launch(Intent(context, MainPreferences::class.java)) + + DrawerAction.HELP_AND_FEEDBACK -> + context.startActivity(Intent(context, HelpAndFeedback::class.java)) + } + }, + onErrorClick = { + context.startActivity(Intent(context, MainPreferences::class.java)) + }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/extensions/Context.kt b/app/src/main/java/org/tasks/extensions/Context.kt index dab0c4d86..7ad895504 100644 --- a/app/src/main/java/org/tasks/extensions/Context.kt +++ b/app/src/main/java/org/tasks/extensions/Context.kt @@ -1,9 +1,11 @@ package org.tasks.extensions +import android.app.Activity import android.content.ActivityNotFoundException import android.content.ContentResolver import android.content.Context import android.content.Context.MODE_PRIVATE +import android.content.ContextWrapper import android.content.Intent import android.content.Intent.ACTION_VIEW import android.content.res.Configuration @@ -92,4 +94,13 @@ object Context { false } } + + fun Context.findActivity(): Activity? { + var context = this + while (context is ContextWrapper) { + if (context is Activity) return context + context = context.baseContext + } + return null + } }