Skip to content
This repository has been archived by the owner on Nov 5, 2024. It is now read-only.

Commit

Permalink
[FEATURE] Advanced features grouping (#3563)
Browse files Browse the repository at this point in the history
* Updated AdvanceD Feature UI

* Reviews resolved

* Reviews resolved
  • Loading branch information
shamim-emon authored Sep 26, 2024
1 parent 4aec53f commit 6ba6690
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 32 deletions.
51 changes: 39 additions & 12 deletions screen/features/src/main/java/com/ivy/features/FeaturesScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Card
Expand All @@ -25,10 +25,11 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ivy.design.system.colors.IvyColors.Gray
import com.ivy.navigation.navigation
import com.ivy.navigation.screenScopedViewModel
import kotlinx.collections.immutable.ImmutableList
Expand Down Expand Up @@ -63,7 +64,7 @@ private fun FeaturesUi(
content = { innerPadding ->
Content(
modifier = Modifier.padding(innerPadding),
features = uiState.features,
items = uiState.featureItemViewStates,
onToggleFeature = {
onEvent(FeaturesUiEvent.ToggleFeature(it))
}
Expand Down Expand Up @@ -104,8 +105,8 @@ private fun Title(

@Composable
private fun Content(
features: ImmutableList<FeatureUi>,
onToggleFeature: (Int) -> Unit,
items: ImmutableList<FeatureItemViewState>,
onToggleFeature: (String) -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(
Expand All @@ -116,19 +117,26 @@ private fun Content(
),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
itemsIndexed(features) { index, item ->
FeatureRow(
feature = item,
onToggleClick = { onToggleFeature(index) }
)
items(items) { item ->
when (item) {
is FeatureItemViewState.FeatureHeaderViewState -> {
FeatureSectionDivider(text = item.name)
}

is FeatureItemViewState.FeatureToggleViewState -> {
FeatureRow(
feature = item,
onToggleClick = { onToggleFeature(item.key) }
)
}
}
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun FeatureRow(
feature: FeatureUi,
feature: FeatureItemViewState.FeatureToggleViewState,
onToggleClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand Down Expand Up @@ -159,3 +167,22 @@ private fun FeatureRow(
}
}
}

@Composable
private fun FeatureSectionDivider(
text: String,
color: Color = Gray
) {
Column {
Spacer(Modifier.height(16.dp))

Text(
modifier = Modifier.padding(start = 16.dp),
text = text,
style = MaterialTheme.typography.titleMedium.copy(
color = color,
fontWeight = FontWeight.Bold
)
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.ivy.features

sealed interface FeaturesUiEvent {
data class ToggleFeature(val index: Int) : FeaturesUiEvent
data class ToggleFeature(val key: String) : FeaturesUiEvent
}
17 changes: 11 additions & 6 deletions screen/features/src/main/java/com/ivy/features/FeaturesUiState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ package com.ivy.features
import kotlinx.collections.immutable.ImmutableList

data class FeaturesUiState(
val features: ImmutableList<FeatureUi>,
val featureItemViewStates: ImmutableList<FeatureItemViewState>,
)

data class FeatureUi(
val name: String,
val enabled: Boolean,
val description: String?,
)
sealed interface FeatureItemViewState {
data class FeatureToggleViewState(
val key: String,
val name: String,
val enabled: Boolean,
val description: String?,
) : FeatureItemViewState

data class FeatureHeaderViewState(val name: String) : FeatureItemViewState
}
48 changes: 35 additions & 13 deletions screen/features/src/main/java/com/ivy/features/FeaturesViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.lifecycle.viewModelScope
import com.ivy.domain.features.BoolFeature
import com.ivy.domain.features.FeatureGroup
import com.ivy.ui.ComposeViewModel
import com.ivy.domain.features.Features
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -23,23 +25,43 @@ class FeaturesViewModel @Inject constructor(
@ApplicationContext
private val context: Context
) : ComposeViewModel<FeaturesUiState, FeaturesUiEvent>() {

@Composable
override fun uiState(): FeaturesUiState {
return FeaturesUiState(
features = getFeatures()
featureItemViewStates = getFeatures()
)
}

@SuppressLint("BuildListAdds")
@Composable
fun getFeatures(): ImmutableList<FeatureUi> {
val allFeatures = features.allFeatures.map {
FeatureUi(
name = it.name ?: it.key,
description = it.description,
enabled = it.asEnabledState()
)
}
return allFeatures.toImmutableList()
fun getFeatures(): ImmutableList<FeatureItemViewState> {
return buildList {
val groups: Map<FeatureGroup?, BoolFeature> =
features.allFeatures
.associateBy { it.group }
.toSortedMap(compareBy { it?.name })

groups.forEach { group ->
add(
FeatureItemViewState.FeatureHeaderViewState(
name = group.key?.name ?: "Undefined"
)
)
val featuresByGroup: List<FeatureItemViewState> = features
.allFeatures
.filter { it.group?.name == group.key?.name }
.map {
FeatureItemViewState.FeatureToggleViewState(
key = it.key,
name = it.name ?: it.key,
description = it.description,
enabled = it.asEnabledState()
)
}
addAll(featuresByGroup)
}
}.toImmutableList()
}

override fun onEvent(event: FeaturesUiEvent) {
Expand All @@ -50,9 +72,9 @@ class FeaturesViewModel @Inject constructor(

private fun toggleFeature(event: FeaturesUiEvent.ToggleFeature) {
viewModelScope.launch {
val feature = features.allFeatures[event.index]
val enabled = feature.enabledFlow(context).first() ?: false
feature.set(context, !enabled)
val feature = features.allFeatures.find { feature -> feature.key == event.key }
val enabled = feature?.enabledFlow(context)?.first() ?: false
feature?.set(context, !enabled)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.map
@Immutable
class BoolFeature(
val key: String,
val group: FeatureGroup? = null,
val name: String? = null,
val description: String? = null,
private val defaultValue: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.ivy.domain.features

enum class FeatureGroup {
Category, Account, Other
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,45 @@ class IvyFeatures @Inject constructor() : Features {

override val sortCategoriesAlphabetically = BoolFeature(
key = "sort_categories_alphabetically",
group = FeatureGroup.Other,
name = "Sort Categories Alphabetically",
description = "Sort income and expenses" +
" categories alphabetically"
)

override val compactAccountsMode = BoolFeature(
key = "compact_account_ui",
group = FeatureGroup.Account,
name = "Compact account UI",
description = "Enables more compact and dense UI for the \"Accounts\" tab"
)

override val compactCategoriesMode = BoolFeature(
key = "compact_categories_ui",
group = FeatureGroup.Category,
name = "Compact category UI",
description = "Activates a more streamlined and space-efficient interface for the \"Categories\" Screen"
)

override val showTitleSuggestions = BoolFeature(
key = "show_title_suggestions",
group = FeatureGroup.Other,
name = "Show previous title suggestions",
description = "Enables display of previous transaction titles when editing or creating a new transaction",
defaultValue = true
)

override val showCategorySearchBar = BoolFeature(
key = "search_categories",
group = FeatureGroup.Category,
name = "Search categories",
description = "Show search bar in category screen",
defaultValue = true
)

override val hideTotalBalance = BoolFeature(
key = "hide_total_balance",
group = FeatureGroup.Account,
name = "Hide total balance",
description = "Enable hide the total balance from the accounts tab",
defaultValue = false
Expand Down

0 comments on commit 6ba6690

Please sign in to comment.