From e4b408ab19c43c436e1ff30e3060f48ba84d725f Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Sat, 24 Sep 2022 06:02:29 +0200 Subject: [PATCH] Add: SortFilter Sheet --- .../fdroid/ui/fragments/SortFilterSheet.kt | 236 ++++++++++++++++++ src/main/res/values/strings.xml | 3 + 2 files changed, 239 insertions(+) create mode 100644 src/main/kotlin/com/machiav3lli/fdroid/ui/fragments/SortFilterSheet.kt diff --git a/src/main/kotlin/com/machiav3lli/fdroid/ui/fragments/SortFilterSheet.kt b/src/main/kotlin/com/machiav3lli/fdroid/ui/fragments/SortFilterSheet.kt new file mode 100644 index 00000000..e0622f58 --- /dev/null +++ b/src/main/kotlin/com/machiav3lli/fdroid/ui/fragments/SortFilterSheet.kt @@ -0,0 +1,236 @@ +package com.machiav3lli.fdroid.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.rememberNestedScrollInteropConnection +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.google.accompanist.flowlayout.FlowRow +import com.google.accompanist.flowlayout.MainAxisAlignment +import com.machiav3lli.fdroid.MainApplication +import com.machiav3lli.fdroid.R +import com.machiav3lli.fdroid.content.Preferences +import com.machiav3lli.fdroid.index.RepositoryUpdater.db +import com.machiav3lli.fdroid.ui.compose.components.ChipsSwitch +import com.machiav3lli.fdroid.ui.compose.components.SelectChip +import com.machiav3lli.fdroid.ui.compose.theme.AppTheme +import com.machiav3lli.fdroid.ui.navigation.NavItem +import com.machiav3lli.fdroid.utility.isDarkTheme + +class SortFilterSheet(val navPage: NavItem) : FullscreenBottomSheetDialogFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + super.onCreate(savedInstanceState) + return ComposeView(requireContext()).apply { + setContent { + AppTheme( + darkTheme = when (Preferences[Preferences.Key.Theme]) { + is Preferences.Theme.System -> isSystemInDarkTheme() + is Preferences.Theme.SystemBlack -> isSystemInDarkTheme() + else -> isDarkTheme + } + ) { + SortFilterPage(navPage) + } + } + } + } + + override fun setupLayout() { + } + + override fun updateSheet() { + } + + @OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) + @Composable + fun SortFilterPage(navPage: NavItem) { + val nestedScrollConnection = rememberNestedScrollInteropConnection() + val dbHandler = ((context as AppCompatActivity).application as MainApplication).db + val repos by dbHandler.repositoryDao.allLive.observeAsState(emptyList()) + val categories by db.categoryDao.allNamesLive.observeAsState(emptyList()) + val activeRepos by remember(repos) { mutableStateOf(repos.filter { it.enabled }) } + + val sortKey = when (navPage) { + NavItem.Latest -> Preferences.Key.SortOrderLatest + NavItem.Installed -> Preferences.Key.SortOrderInstalled + else -> Preferences.Key.SortOrderExplore // NavItem.Explore + } + val sortAscendingKey = when (navPage) { + NavItem.Latest -> Preferences.Key.SortOrderAscendingLatest + NavItem.Installed -> Preferences.Key.SortOrderAscendingInstalled + else -> Preferences.Key.SortOrderAscendingExplore // NavItem.Explore + } + val reposFilterKey = when (navPage) { + NavItem.Latest -> Preferences.Key.ReposFilterLatest + NavItem.Installed -> Preferences.Key.ReposFilterInstalled + else -> Preferences.Key.ReposFilterExplore // NavItem.Explore + } + val categoriesFilterKey = when (navPage) { + NavItem.Latest -> Preferences.Key.CategoriesFilterLatest + NavItem.Installed -> Preferences.Key.CategoriesFilterInstalled + else -> Preferences.Key.CategoriesFilterExplore // NavItem.Explore + } + + Scaffold() { paddingValues -> + LazyColumn( + modifier = Modifier + .padding(paddingValues) + .nestedScroll(nestedScrollConnection) + .fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(8.dp), + contentPadding = PaddingValues(8.dp) + ) { + item { + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.sorting_order), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleLarge + ) + FlowRow( + modifier = Modifier.fillMaxWidth(), + mainAxisSpacing = 8.dp, + crossAxisSpacing = 4.dp, + mainAxisAlignment = MainAxisAlignment.Center, + ) { + var selected by remember { + mutableStateOf( + Preferences[sortKey] + ) + } + + sortKey.default.value.values.forEach { + SelectChip( + text = stringResource(id = it.order.titleResId), + checked = it == selected + ) { + Preferences[sortKey] = it + selected = it + } + } + } + var ascending by remember { + mutableStateOf(Preferences[sortAscendingKey]) + } + + ChipsSwitch( + firstTextId = R.string.sort_ascending, + firstIconId = R.drawable.ic_arrow_up, + secondTextId = R.string.sort_descending, + secondIconId = R.drawable.ic_arrow_down, + firstSelected = ascending, + onCheckedChange = { checked -> + ascending = checked + Preferences[sortAscendingKey] = checked + } + ) + } + item { + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.repositories), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleLarge + ) + FlowRow( + modifier = Modifier.fillMaxWidth(), + mainAxisSpacing = 8.dp, + crossAxisSpacing = 4.dp, + mainAxisAlignment = MainAxisAlignment.Center, + ) { + activeRepos.forEach { + var checked by remember { + mutableStateOf( + !Preferences[reposFilterKey] + .contains(it.id.toString()) + ) + } + + SelectChip( + text = it.name, + checked = checked + ) { + checked = !checked + if (checked) + Preferences[reposFilterKey] = + Preferences[reposFilterKey] + .minus(it.id.toString()) + else + Preferences[reposFilterKey] = + Preferences[reposFilterKey] + .plus(it.id.toString()) + } + } + } + } + item { + Text( + modifier = Modifier.fillMaxWidth(), + text = stringResource(id = R.string.categories), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleLarge + ) + FlowRow( + modifier = Modifier.fillMaxWidth(), + mainAxisSpacing = 8.dp, + crossAxisSpacing = 4.dp, + mainAxisAlignment = MainAxisAlignment.Center, + ) { + categories.sorted().forEach { + var checked by remember { + mutableStateOf( + !Preferences[categoriesFilterKey].contains(it) + ) + } + + SelectChip( + text = it, + checked = checked + ) { + checked = !checked + if (checked) + Preferences[categoriesFilterKey] = + Preferences[categoriesFilterKey] + .minus(it) + else + Preferences[categoriesFilterKey] = + Preferences[categoriesFilterKey] + .plus(it) + } + } + } + } + } + } + } +} diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index c8272b87..c76b634f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -219,4 +219,7 @@ Our Telegram group Our Matrix group minSDK + Categories + Ascending + Descending