mirror of
https://github.com/f-droid/fdroidclient.git
synced 2026-04-23 16:29:28 -04:00
group categories on discover screen
in order to make them easier to parse/browse through
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
package org.fdroid.ui.categories
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import org.fdroid.next.R
|
||||
|
||||
data class CategoryGroup(
|
||||
val id: String,
|
||||
@get:StringRes
|
||||
val name: Int,
|
||||
)
|
||||
|
||||
object CategoryGroups {
|
||||
val productivity = CategoryGroup("productivity", R.string.category_group_productivity)
|
||||
val tools = CategoryGroup("tools", R.string.category_group_tools)
|
||||
val wallets = CategoryGroup("wallets", R.string.category_group_wallets)
|
||||
val media = CategoryGroup("media", R.string.category_group_media)
|
||||
val communication = CategoryGroup("communication", R.string.category_group_communication)
|
||||
val device = CategoryGroup("device", R.string.category_group_device)
|
||||
val storage = CategoryGroup("storage", R.string.category_group_storage)
|
||||
val interests = CategoryGroup("interests", R.string.category_group_interests)
|
||||
val misc = CategoryGroup("misc", R.string.category_group_misc)
|
||||
}
|
||||
@@ -126,4 +126,67 @@ data class CategoryItem(val id: String, val name: String) {
|
||||
"Writing" -> Icons.Default.EditNote
|
||||
else -> Icons.Default.Category
|
||||
}
|
||||
val group: CategoryGroup
|
||||
get() = when (id) {
|
||||
"App Store & Updater" -> CategoryGroups.device
|
||||
"Bookmark" -> CategoryGroups.storage
|
||||
"Browser" -> CategoryGroups.productivity
|
||||
"Calculator" -> CategoryGroups.tools
|
||||
"Calendar & Agenda" -> CategoryGroups.productivity
|
||||
"Cloud Storage & File Sync" -> CategoryGroups.storage
|
||||
"Connectivity" -> CategoryGroups.device
|
||||
"Development" -> CategoryGroups.interests
|
||||
"DNS & Hosts" -> CategoryGroups.device
|
||||
"Draw" -> CategoryGroups.interests
|
||||
"Ebook Reader" -> CategoryGroups.media
|
||||
"Email" -> CategoryGroups.communication
|
||||
"File Encryption & Vault" -> CategoryGroups.storage
|
||||
"File Transfer" -> CategoryGroups.storage
|
||||
"Finance Manager" -> CategoryGroups.wallets
|
||||
"Forum" -> CategoryGroups.communication
|
||||
"Gallery" -> CategoryGroups.storage
|
||||
"Games" -> CategoryGroups.media
|
||||
"Graphics" -> CategoryGroups.interests
|
||||
"Habit Tracker" -> CategoryGroups.productivity
|
||||
"Icon Pack" -> CategoryGroups.device
|
||||
"Internet" -> CategoryGroups.productivity
|
||||
"Keyboard & IME" -> CategoryGroups.device
|
||||
"Launcher" -> CategoryGroups.device
|
||||
"Local Media Player" -> CategoryGroups.media
|
||||
"Messaging" -> CategoryGroups.communication
|
||||
"Money" -> CategoryGroups.wallets
|
||||
"Multimedia" -> CategoryGroups.media
|
||||
"Music Practice Tool" -> CategoryGroups.interests
|
||||
"Navigation" -> CategoryGroups.tools
|
||||
"News" -> CategoryGroups.interests
|
||||
"Note" -> CategoryGroups.storage
|
||||
"Online Media Player" -> CategoryGroups.media
|
||||
"Pass Wallet" -> CategoryGroups.wallets
|
||||
"Password & 2FA" -> CategoryGroups.device
|
||||
"Phone & SMS" -> CategoryGroups.communication
|
||||
"Podcast" -> CategoryGroups.media
|
||||
"Public Transport" -> CategoryGroups.tools
|
||||
"Reading" -> CategoryGroups.media
|
||||
"Recipe Manager" -> CategoryGroups.interests
|
||||
"Science & Education" -> CategoryGroups.interests
|
||||
"Security" -> CategoryGroups.device
|
||||
"Shopping List" -> CategoryGroups.tools
|
||||
"Social Network" -> CategoryGroups.communication
|
||||
"Sports & Health" -> CategoryGroups.interests
|
||||
"System" -> CategoryGroups.device
|
||||
"Task" -> CategoryGroups.productivity
|
||||
"Text Editor" -> CategoryGroups.productivity
|
||||
"Theming" -> CategoryGroups.device
|
||||
"Time" -> CategoryGroups.productivity
|
||||
"Translation & Dictionary" -> CategoryGroups.tools
|
||||
"Voice & Video Chat" -> CategoryGroups.communication
|
||||
"Unit Convertor" -> CategoryGroups.tools
|
||||
"VPN & Proxy" -> CategoryGroups.device
|
||||
"Wallet" -> CategoryGroups.wallets
|
||||
"Wallpaper" -> CategoryGroups.device
|
||||
"Weather" -> CategoryGroups.tools
|
||||
"Workout" -> CategoryGroups.interests
|
||||
"Writing" -> CategoryGroups.productivity
|
||||
else -> CategoryGroups.misc
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -19,11 +21,11 @@ import org.fdroid.ui.lists.AppListType
|
||||
|
||||
@Composable
|
||||
fun CategoryList(
|
||||
categories: List<CategoryItem>?,
|
||||
categoryMap: Map<CategoryGroup, List<CategoryItem>>?,
|
||||
onNav: (NavKey) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (categories != null) Column(
|
||||
if (categoryMap != null) Column(
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(
|
||||
@@ -31,15 +33,28 @@ fun CategoryList(
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
modifier = Modifier.padding(bottom = 8.dp, start = 4.dp),
|
||||
)
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
categories.forEach { category ->
|
||||
CategoryChip(category, {
|
||||
val type = AppListType.Category(category.name, category.id)
|
||||
val navKey = NavigationKey.AppList(type)
|
||||
onNav(navKey)
|
||||
})
|
||||
// we'll sort the groups here, because before we didn't have the context to get names
|
||||
val context = LocalContext.current
|
||||
val sortedMap = remember(categoryMap) {
|
||||
val comparator = compareBy<CategoryGroup> { context.getString(it.name) }
|
||||
categoryMap.toSortedMap(comparator)
|
||||
}
|
||||
sortedMap.forEach { (group, categories) ->
|
||||
Text(
|
||||
text = stringResource(group.name),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
modifier = Modifier.padding(4.dp),
|
||||
)
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
categories.forEach { category ->
|
||||
CategoryChip(category, {
|
||||
val type = AppListType.Category(category.name, category.id)
|
||||
val navKey = NavigationKey.AppList(type)
|
||||
onNav(navKey)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,14 +64,18 @@ fun CategoryList(
|
||||
@Composable
|
||||
fun CategoryListPreview() {
|
||||
FDroidContent {
|
||||
val categories = listOf(
|
||||
CategoryItem("App Store & Updater", "App Store & Updater"),
|
||||
CategoryItem("Browser", "Browser"),
|
||||
CategoryItem("Calendar & Agenda", "Calendar & Agenda"),
|
||||
CategoryItem("Cloud Storage & File Sync", "Cloud Storage & File Sync"),
|
||||
CategoryItem("Connectivity", "Connectivity"),
|
||||
CategoryItem("Development", "Development"),
|
||||
CategoryItem("doesn't exist", "Foo bar"),
|
||||
val categories = mapOf(
|
||||
CategoryGroups.productivity to listOf(
|
||||
CategoryItem("App Store & Updater", "App Store & Updater"),
|
||||
CategoryItem("Browser", "Browser"),
|
||||
CategoryItem("Calendar & Agenda", "Calendar & Agenda"),
|
||||
),
|
||||
CategoryGroups.media to listOf(
|
||||
CategoryItem("Cloud Storage & File Sync", "Cloud Storage & File Sync"),
|
||||
CategoryItem("Connectivity", "Connectivity"),
|
||||
CategoryItem("Development", "Development"),
|
||||
CategoryItem("doesn't exist", "Foo bar"),
|
||||
)
|
||||
)
|
||||
CategoryList(categories, {})
|
||||
}
|
||||
|
||||
@@ -171,10 +171,11 @@ fun Discover(
|
||||
}
|
||||
AnimatedVisibility(discoverModel is LoadedDiscoverModel) {
|
||||
CategoryList(
|
||||
categories = (discoverModel as LoadedDiscoverModel).categories,
|
||||
categoryMap = (discoverModel as LoadedDiscoverModel).categories,
|
||||
onNav = onNav,
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 16.dp)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.fdroid.database.Repository
|
||||
import org.fdroid.ui.categories.CategoryGroup
|
||||
import org.fdroid.ui.categories.CategoryItem
|
||||
|
||||
@Composable
|
||||
@@ -34,7 +35,7 @@ fun DiscoverPresenter(
|
||||
LoadedDiscoverModel(
|
||||
newApps = apps.filter { it.isNew },
|
||||
recentlyUpdatedApps = apps.filter { !it.isNew },
|
||||
categories = categories,
|
||||
categories = categories?.groupBy { it.group },
|
||||
searchResults = searchResults,
|
||||
)
|
||||
}
|
||||
@@ -46,6 +47,6 @@ object NoEnabledReposDiscoverModel : DiscoverModel()
|
||||
data class LoadedDiscoverModel(
|
||||
val newApps: List<AppDiscoverItem>,
|
||||
val recentlyUpdatedApps: List<AppDiscoverItem>,
|
||||
val categories: List<CategoryItem>?,
|
||||
val categories: Map<CategoryGroup, List<CategoryItem>>?,
|
||||
val searchResults: SearchResults? = null,
|
||||
) : DiscoverModel()
|
||||
|
||||
@@ -61,7 +61,7 @@ class DiscoverViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
}
|
||||
val categories = db.getRepositoryDao().getLiveCategories().asFlow().map { categories ->
|
||||
private val categories = db.getRepositoryDao().getLiveCategories().asFlow().map { categories ->
|
||||
categories.map { category ->
|
||||
CategoryItem(
|
||||
id = category.id,
|
||||
|
||||
@@ -36,6 +36,16 @@
|
||||
<string name="filter_selected">selected</string>
|
||||
<string name="category">Category</string>
|
||||
|
||||
<string name="category_group_productivity">Productivity</string>
|
||||
<string name="category_group_tools">Tools</string>
|
||||
<string name="category_group_wallets">Digital Wallets</string>
|
||||
<string name="category_group_media">Entertainment & Media</string>
|
||||
<string name="category_group_communication">Communication</string>
|
||||
<string name="category_group_device">Device</string>
|
||||
<string name="category_group_storage">Files & Storage</string>
|
||||
<string name="category_group_interests">Interests</string>
|
||||
<string name="category_group_misc">Miscellaneous</string>
|
||||
|
||||
<string name="author_by">By %1$s</string>
|
||||
<string name="last_updated">Last updated: %1$s</string>
|
||||
<!-- The placeholder in round brackets will be replaced with the size of the app -->
|
||||
|
||||
Reference in New Issue
Block a user