Skip to content

Commit

Permalink
Merge pull request #721 from Orange-OpenSource/699-tabs-review-the-cu…
Browse files Browse the repository at this point in the history
…stomization

699 - Tabs - Change customization options
  • Loading branch information
florentmaitre authored Nov 30, 2023
2 parents 317b087 + 52631f8 commit 47921a6
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 45 deletions.
21 changes: 13 additions & 8 deletions app/src/main/java/com/orange/ods/app/ui/AppBarTabsState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,18 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.snapshots.SnapshotStateList
import com.orange.ods.app.ui.components.tabs.MainTabsCustomizationState
import com.orange.ods.app.ui.utilities.NavigationItem
import com.orange.ods.app.ui.utilities.rememberSaveableMutableStateListOf
import com.orange.ods.compose.component.tab.OdsTabRow

/**
* Tabs state source of truth.
*/
@OptIn(ExperimentalFoundationApi::class)
class AppBarTabsState(
val tabs: SnapshotStateList<NavigationItem>,
val tabIconType: MutableState<MainTabsCustomizationState.TabIconType>,
val tabsIconPosition: MutableState<OdsTabRow.Tab.Icon.Position>,
val tabIconEnabled: MutableState<Boolean>,
val tabTextEnabled: MutableState<Boolean>,
val scrollableTabs: MutableState<Boolean>
) {
Expand All @@ -38,7 +39,8 @@ class AppBarTabsState(
scrollableTabs = false,
tabs = emptyList(),
pagerState = null,
tabIconType = MainTabsCustomizationState.TabIconType.Top,
tabsIconPosition = OdsTabRow.Tab.Icon.Position.Top,
tabIconEnabled = true,
tabTextEnabled = true,
)
}
Expand All @@ -55,7 +57,8 @@ class AppBarTabsState(
addAll(tabsConfiguration.tabs)
}
pagerState = tabsConfiguration.pagerState
tabIconType.value = tabsConfiguration.tabIconType
tabsIconPosition.value = tabsConfiguration.tabsIconPosition
tabIconEnabled.value = tabsConfiguration.tabIconEnabled
tabTextEnabled.value = tabsConfiguration.tabTextEnabled
scrollableTabs.value = tabsConfiguration.scrollableTabs
}
Expand All @@ -69,18 +72,20 @@ class AppBarTabsState(
@Composable
fun rememberAppBarTabsState(
tabs: SnapshotStateList<NavigationItem> = rememberSaveableMutableStateListOf(),
tabIconType: MutableState<MainTabsCustomizationState.TabIconType> = rememberSaveable { mutableStateOf(AppBarTabsState.DefaultConfiguration.tabIconType) },
tabsIconPosition: MutableState<OdsTabRow.Tab.Icon.Position> = rememberSaveable { mutableStateOf(AppBarTabsState.DefaultConfiguration.tabsIconPosition) },
tabIconEnabled: MutableState<Boolean> = rememberSaveable { mutableStateOf(AppBarTabsState.DefaultConfiguration.tabIconEnabled) },
tabTextEnabled: MutableState<Boolean> = rememberSaveable { mutableStateOf(AppBarTabsState.DefaultConfiguration.tabTextEnabled) },
scrollableTabs: MutableState<Boolean> = rememberSaveable { mutableStateOf(AppBarTabsState.DefaultConfiguration.scrollableTabs) }
) = remember(tabs, tabIconType, tabTextEnabled, scrollableTabs) {
AppBarTabsState(tabs, tabIconType, tabTextEnabled, scrollableTabs)
) = remember(tabs, tabsIconPosition, tabIconEnabled, tabTextEnabled, scrollableTabs) {
AppBarTabsState(tabs, tabsIconPosition, tabIconEnabled, tabTextEnabled, scrollableTabs)
}

@OptIn(ExperimentalFoundationApi::class)
data class TabsConfiguration(
val scrollableTabs: Boolean,
val tabs: List<NavigationItem>,
val pagerState: PagerState?,
val tabIconType: MainTabsCustomizationState.TabIconType,
val tabsIconPosition: OdsTabRow.Tab.Icon.Position,
val tabIconEnabled: Boolean,
val tabTextEnabled: Boolean
)
11 changes: 4 additions & 7 deletions app/src/main/java/com/orange/ods/app/ui/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.orange.ods.app.R
import com.orange.ods.app.domain.recipes.LocalCategories
import com.orange.ods.app.domain.recipes.LocalRecipes
import com.orange.ods.app.ui.components.tabs.MainTabsCustomizationState
import com.orange.ods.app.ui.components.tabs.tabs
import com.orange.ods.app.ui.utilities.extension.isDarkModeEnabled
import com.orange.ods.app.ui.utilities.extension.isOrange
Expand Down Expand Up @@ -195,30 +194,28 @@ private fun AppBarTabs(appBarTabsState: AppBarTabsState) {
// Do not use tabs directly because this is a SnapshotStateList
// Thus its value can be modified and can lead to crashes if it becomes empty
val tabs = tabs.toList()
val tabIconPosition =
if (tabIconType.value == MainTabsCustomizationState.TabIconType.Leading && tabTextEnabled.value) OdsTabRow.Tab.Icon.Position.Leading else OdsTabRow.Tab.Icon.Position.Top

if (scrollableTabs.value) {
OdsScrollableTabRow(
selectedTabIndex = pagerState.currentPage,
tabs = tabs(
tabs = tabs,
pagerState = pagerState,
tabIconType = tabIconType.value,
tabIconEnabled = tabIconEnabled.value,
tabTextEnabled = tabTextEnabled.value
),
tabIconPosition = tabIconPosition
tabIconPosition = tabsIconPosition.value
)
} else {
OdsTabRow(
selectedTabIndex = pagerState.currentPage,
tabs = tabs(
tabs = tabs,
pagerState = pagerState,
tabIconType = tabIconType.value,
tabIconEnabled = tabIconEnabled.value,
tabTextEnabled = tabTextEnabled.value
),
tabIconPosition = tabIconPosition
tabIconPosition = tabsIconPosition.value
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.orange.ods.app.ui.utilities.composable.Subtitle
import com.orange.ods.compose.component.chip.OdsChoiceChip
import com.orange.ods.compose.component.chip.OdsChoiceChipsFlowRow
import com.orange.ods.compose.component.listitem.OdsListItem
import com.orange.ods.compose.component.tab.OdsTabRow
import com.orange.ods.compose.text.OdsTextBody1

private const val MinFixedTabCount = 2
Expand Down Expand Up @@ -62,7 +63,7 @@ fun ComponentTabs(variant: Variant, upPress: () -> Unit) {

with(tabsCustomizationState) {
LocalAppBarManager.current.updateAppBarTabs(
TabsConfiguration(scrollableTabs, tabs, pagerState, tabIconType.value, tabTextEnabled.value)
TabsConfiguration(scrollableTabs, tabs, pagerState, tabsIconPosition.value, tabIconEnabled.value, tabTextEnabled.value)
)

BackHandler {
Expand All @@ -72,32 +73,32 @@ fun ComponentTabs(variant: Variant, upPress: () -> Unit) {
ComponentCustomizationBottomSheetScaffold(
bottomSheetScaffoldState = bottomSheetScaffoldState,
bottomSheetContent = {
Subtitle(textRes = R.string.component_element_icon, horizontalPadding = true)
OdsListItem(
text = stringResource(id = R.string.component_tab_text),
trailing = OdsListItem.TrailingSwitch(tabTextEnabled.value, { tabTextEnabled.value = it }, isTabTextCustomizationEnabled)
)
OdsListItem(
text = stringResource(id = R.string.component_tab_icon),
trailing = OdsListItem.TrailingSwitch(tabIconEnabled.value, { tabIconEnabled.value = it }, isTabIconCustomizationEnabled)
)
Subtitle(textRes = R.string.component_tabs_icon_position, horizontalPadding = true)
OdsChoiceChipsFlowRow(
value = tabIconType.value,
onValueChange = { value -> tabIconType.value = value },
value = tabsIconPosition.value,
onValueChange = { value -> tabsIconPosition.value = value },
modifier = Modifier.padding(horizontal = dimensionResource(id = com.orange.ods.R.dimen.spacing_m)),
chips = listOf(
OdsChoiceChip(
text = stringResource(id = R.string.component_tab_icon_leading), value = MainTabsCustomizationState.TabIconType.Leading,
enabled = isTabIconCustomizationEnabled
text = stringResource(id = R.string.component_tabs_icon_position_leading),
value = OdsTabRow.Tab.Icon.Position.Leading,
enabled = isTabsIconPositionEnabled
),
OdsChoiceChip(
text = stringResource(id = R.string.component_tab_icon_top), value = MainTabsCustomizationState.TabIconType.Top,
enabled = isTabIconCustomizationEnabled
),
OdsChoiceChip(
text = stringResource(id = R.string.component_element_none), value = MainTabsCustomizationState.TabIconType.None,
enabled = isTabIconCustomizationEnabled
text = stringResource(id = R.string.component_tabs_icon_position_top), value = OdsTabRow.Tab.Icon.Position.Top,
enabled = isTabsIconPositionEnabled
)
)
)

OdsListItem(
text = stringResource(id = R.string.component_element_text),
trailing = OdsListItem.TrailingSwitch(tabTextEnabled.value, { tabTextEnabled.value = it }, isTabTextCustomizationEnabled)
)

ComponentCountRow(
modifier = Modifier.padding(start = dimensionResource(id = com.orange.ods.R.dimen.screen_horizontal_margin)),
title = stringResource(id = R.string.component_tabs_count),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,42 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import com.orange.ods.app.ui.utilities.NavigationItem
import com.orange.ods.compose.component.tab.OdsTabRow

@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
@Composable
fun rememberMainTabsCustomizationState(
bottomSheetScaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(),
tabsCount: MutableState<Int>,
pagerState: PagerState = rememberPagerState(),
selectedTabIconType: MutableState<MainTabsCustomizationState.TabIconType> = rememberSaveable { mutableStateOf(MainTabsCustomizationState.TabIconType.Top) },
selectedTabsIconPosition: MutableState<OdsTabRow.Tab.Icon.Position> = rememberSaveable { mutableStateOf(OdsTabRow.Tab.Icon.Position.Top) },
tabIconEnabled: MutableState<Boolean> = rememberSaveable { mutableStateOf(true) },
tabTextEnabled: MutableState<Boolean> = rememberSaveable { mutableStateOf(true) }
) =
remember(bottomSheetScaffoldState, pagerState, tabsCount, selectedTabIconType, tabTextEnabled) {
MainTabsCustomizationState(bottomSheetScaffoldState, pagerState, tabsCount, selectedTabIconType, tabTextEnabled)
remember(bottomSheetScaffoldState, pagerState, tabsCount, selectedTabsIconPosition, tabIconEnabled, tabTextEnabled) {
MainTabsCustomizationState(bottomSheetScaffoldState, pagerState, tabsCount, selectedTabsIconPosition, tabIconEnabled, tabTextEnabled)
}

@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
class MainTabsCustomizationState(
val bottomSheetScaffoldState: BottomSheetScaffoldState,
val pagerState: PagerState,
val tabsCount: MutableState<Int>,
val tabIconType: MutableState<TabIconType>,
val tabsIconPosition: MutableState<OdsTabRow.Tab.Icon.Position>,
val tabIconEnabled: MutableState<Boolean>,
val tabTextEnabled: MutableState<Boolean>
) {
enum class TabIconType {
Leading, Top, None
}

private val availableTabs = NavigationItem.values().toList()

val isTabTextCustomizationEnabled: Boolean
get() = tabIconType.value != TabIconType.None
get() = tabIconEnabled.value

val isTabIconCustomizationEnabled: Boolean
get() = tabTextEnabled.value

val isTabsIconPositionEnabled: Boolean
get() = isTabIconCustomizationEnabled && isTabTextCustomizationEnabled

val tabs: List<NavigationItem>
get() = availableTabs.take(tabsCount.value.coerceAtLeast(0))
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ import kotlinx.coroutines.launch
fun tabs(
tabs: List<NavigationItem>,
pagerState: PagerState,
tabIconType: MainTabsCustomizationState.TabIconType,
tabIconEnabled: Boolean,
tabTextEnabled: Boolean,
): List<OdsTabRow.Tab> {
val scope = rememberCoroutineScope()

return tabs.mapIndexed { index, tab ->
OdsTabRow.Tab(
icon = if (tabIconType != MainTabsCustomizationState.TabIconType.None) OdsTabRow.Tab.Icon(painter = painterResource(id = tab.iconResId)) else null,
icon = if (tabIconEnabled) OdsTabRow.Tab.Icon(painter = painterResource(id = tab.iconResId)) else null,
text = if (tabTextEnabled) stringResource(id = tab.textResId) else null,
) {
scope.launch {
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,11 @@
<string name="component_tabs_count">Tabs count</string>
<string name="component_tabs_remove_tab">Remove tab</string>
<string name="component_tabs_add_tab">Add tab</string>
<string name="component_tab_icon_leading">Leading</string>
<string name="component_tab_icon_top">Top</string>
<string name="component_tabs_icon_position">Icon position</string>
<string name="component_tabs_icon_position_leading">Leading</string>
<string name="component_tabs_icon_position_top">Top</string>
<string name="component_tab_icon">Icon</string>
<string name="component_tab_text">Text</string>

<!-- Modules -->
<string name="modules_coming_soon">Coming soon…</string>
Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- \[App\] Change tabs customization to be closer to the API ([#699](https://github.com/Orange-OpenSource/ods-android/issues/699))
- \[Lib\] Rename `OdsImageTile` to `OdsImageItem` ([#683](https://github.com/Orange-OpenSource/ods-android/issues/683))
- \[Lib\] Update `OdsTab`, `OdsLeadingIconTab`, `OdsTabRow` and `OdsScrollableTabRow` APIs ([#675](https://github.com/Orange-OpenSource/ods-android/issues/675))
- \[Lib\] Update `OdsTextField`, `OdsPasswordTextField` and `OdsSearchTextField` APIs ([#676](https://github.com/Orange-OpenSource/ods-android/issues/676))
Expand Down

0 comments on commit 47921a6

Please sign in to comment.