Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

349 - Top app bar - Fix overflow menu colors for all themes #361

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes done in ODS library will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased](https://github.com/Orange-OpenSource/ods-android/compare/0.8.0...master)

### Added

- \[Lib\] Add `OdsTopAppBarOverflowMenuBox` and `OdsDropdownMenu` composables to display an overflow menu in the top app bar ([#349](https://github.com/Orange-OpenSource/ods-android/issues/349))

### Fixed

- \[Lib\] Fix top app bar overflow menu colors ([#349](https://github.com/Orange-OpenSource/ods-android/issues/349))

## [0.8.0](https://github.com/Orange-OpenSource/ods-android/compare/0.7.0...0.8.0) - 2022-12-07

### Added
Expand Down
56 changes: 15 additions & 41 deletions demo/src/main/java/com/orange/ods/demo/ui/MainTopAppBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,18 @@ package com.orange.ods.demo.ui

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Box
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import com.orange.ods.compose.component.appbar.top.OdsTopAppBar
import com.orange.ods.compose.component.appbar.top.OdsTopAppBarActionButton
import com.orange.ods.compose.text.OdsTextBody1
import com.orange.ods.compose.component.appbar.top.OdsTopAppBarOverflowMenuBox
import com.orange.ods.compose.component.menu.OdsDropdownMenuItem
import com.orange.ods.demo.R
import com.orange.ods.demo.ui.components.utilities.clickOnElement
import com.orange.ods.demo.ui.utilities.extension.isDarkModeEnabled
Expand Down Expand Up @@ -72,7 +64,18 @@ fun MainTopAppBar(
}
}
if (state.isOverflowMenuEnabled) {
OverflowMenu()
OdsTopAppBarOverflowMenuBox(
overflowIconContentDescription = stringResource(id = R.string.component_app_bars_top_element_overflow_menu)
) {
OdsDropdownMenuItem(
text = stringResource(id = R.string.component_app_bars_top_action_account),
onClick = { clickOnElement(context, context.getString(R.string.component_app_bars_top_action_account)) }
)
OdsDropdownMenuItem(
text = stringResource(id = R.string.component_app_bars_top_action_settings),
onClick = { clickOnElement(context, context.getString(R.string.component_app_bars_top_action_settings)) }
)
}
}
},
elevated = false // elevation is managed in [MainScreen] cause of tabs
Expand Down Expand Up @@ -104,39 +107,10 @@ private fun TopAppBarChangeModeActionButton() {
)
}

@Composable
private fun OverflowMenu() {
var showMenu by remember { mutableStateOf(false) }
val context = LocalContext.current

Box {
OdsTopAppBarActionButton(
onClick = { showMenu = !showMenu },
painter = rememberVectorPainter(image = Icons.Filled.MoreVert),
contentDescription = stringResource(id = R.string.component_app_bars_top_element_overflow_menu)
)
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
topAppBarDemoOverflowActions.forEach {
DropdownMenuItem(onClick = { clickOnElement(context, context.getString(it.titleRes)) }) {
OdsTextBody1(text = stringResource(id = it.titleRes))
}
}
}
}

}

private val topAppBarDemoActions = listOf(
TopAppBarAction(R.drawable.ic_heart, R.string.component_app_bars_top_action_favourites),
TopAppBarAction(R.drawable.ic_alert, R.string.component_app_bars_top_action_alerts),
)

private val topAppBarDemoOverflowActions = listOf(
TopAppBarAction(R.drawable.ic_account, R.string.component_app_bars_top_action_account),
TopAppBarAction(R.drawable.ic_settings, R.string.component_app_bars_top_action_settings)
)
private data class TopAppBarAction(@DrawableRes val iconRes: Int, @StringRes val titleRes: Int)

private data class TopAppBarAction(@DrawableRes val iconRes: Int, @StringRes val titleRes: Int)
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ fun ComponentTopAppBar() {
)

}) {
// Nothing to display in screen
// Nothing to display in screen (see MainTopAppBar.kt)
}
}
28 changes: 28 additions & 0 deletions docs/components/AppBarsTop.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ description: Top app bars display information and actions relating to the curren
* [Specifications references](#specifications-references)
* [Accessibility](#accessibility)
* [Implementation](#implementation)
* [Extras](#extras)
* [Overflow menu](#overflow-menu)
* [Component specific tokens](#component-specific-tokens)

---
Expand Down Expand Up @@ -236,6 +238,32 @@ If you need to have a top app bar with some elevation you can set the `@style/Wi
</androidx.coordinatorlayout.widget.CoordinatorLayout>
```

## Extras

### Overflow menu

![Overflow menu light](images/app_bar_top_overflow_menu_light.png)
![Overflow menu dark](images/app_bar_top_overflow_menu_dark.png)

You can easily add an overflow menu to your top app bar by using the `OdsTopAppBarOverflowMenuBox` composable as follow:

```kotlin
OdsTopAppBarOverflowMenuBox(overflowIconContentDescription = "more actions") {
OdsDropdownMenuItem(
text = "account",
onClick = {
// Do something
}
)
OdsDropdownMenuItem(
text = "settings",
onClick = {
// Do something
}
)
}
```

## Component specific tokens

_Soon available_
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

package com.orange.ods.compose.component.appbar.top

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.AppBarDefaults
Expand All @@ -19,13 +21,21 @@ import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.orange.ods.compose.component.OdsComponentApi
import com.orange.ods.compose.component.button.OdsIconButton
import com.orange.ods.compose.component.menu.OdsDropdownMenu
import com.orange.ods.compose.component.menu.OdsDropdownMenuItem
import com.orange.ods.compose.component.utilities.Preview
import com.orange.ods.compose.component.utilities.UiModePreviews
import com.orange.ods.compose.theme.OdsTheme
Expand Down Expand Up @@ -79,6 +89,16 @@ fun OdsTopAppBar(
)
}

/**
* Action icon button displayed in an [OdsTopAppBar].
*
* @param onClick Will be called when the user clicks on the action icon button.
* @param painter Painter of the icon.
* @param contentDescription The content description associated to this OdsTopAppBarActionButton.
* @param modifier The [Modifier] to be applied to this OdsTopAppBarActionButton.
* @param enabled whether or not this OdsTopAppBarActionButton will handle input events and appear enabled for
* semantics purposes, true by default.
*/
@Composable
@OdsComponentApi
fun OdsTopAppBarActionButton(
Expand All @@ -98,6 +118,33 @@ fun OdsTopAppBarActionButton(
)
}

/**
* Overflow menu displayed in an [OdsTopAppBar]. It displays the overflow icon (3 vertical dots) and the menu appearing on click.
*
* @param overflowIconContentDescription The content description of the overflow icon.
* @param content The content of the overflow dropdown menu
*/
@Composable
fun OdsTopAppBarOverflowMenuBox(
overflowIconContentDescription: String,
content: @Composable ColumnScope.() -> Unit
) {
var showMenu by remember { mutableStateOf(false) }

Box {
OdsTopAppBarActionButton(
onClick = { showMenu = !showMenu },
painter = rememberVectorPainter(image = Icons.Filled.MoreVert),
contentDescription = overflowIconContentDescription
)
OdsDropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false },
content = content
)
}
}

@UiModePreviews.Default
@Composable
private fun PreviewOdsTopAppBar() = Preview {
Expand All @@ -114,6 +161,12 @@ private fun PreviewOdsTopAppBar() = Preview {
painter = painterResource(id = android.R.drawable.ic_dialog_info),
contentDescription = "Info"
)
OdsTopAppBarOverflowMenuBox(
overflowIconContentDescription = "more options"
) {
OdsDropdownMenuItem(text = "settings", onClick = { })
OdsDropdownMenuItem(text = "account", onClick = { })
}
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
*
* Copyright 2021 Orange
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* /
*/

package com.orange.ods.compose.component.menu

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.PopupProperties
import com.orange.ods.compose.component.utilities.Preview
import com.orange.ods.compose.component.utilities.UiModePreviews
import com.orange.ods.compose.theme.OdsTheme

/**
* <a href="https://system.design.orange.com/0c1af118d/p/07a69b-menus/b/862cbb" class="external" target="_blank">ODS menus</a>.
*
* @see androidx.compose.material.DropdownMenu
*
* @param expanded Whether the menu is currently open and visible to the user
* @param onDismissRequest Called when the user requests to dismiss the menu, such as by
* tapping outside the menu's bounds
* @param modifier The modifier to be applied to the menu
* @param offset [DpOffset] to be added to the position of the menu
florentmaitre marked this conversation as resolved.
Show resolved Hide resolved
* @param properties [PopupProperties] for further customization of the popup's behavior
* @param content The content of the dropdown menu
*/
@Composable
fun OdsDropdownMenu(
florentmaitre marked this conversation as resolved.
Show resolved Hide resolved
expanded: Boolean,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
offset: DpOffset = DpOffset(0.dp, 0.dp),
properties: PopupProperties = PopupProperties(focusable = true),
content: @Composable ColumnScope.() -> Unit
) {
DropdownMenu(
expanded = expanded,
onDismissRequest = onDismissRequest,
modifier = modifier.background(OdsTheme.colors.surface),
offset = offset,
properties = properties,
content = content
)
}

/**
* @see androidx.compose.material.DropdownMenuItem
*
* @param text The text of the menu item
* @param onClick Called when the menu item was clicked
* @param enabled Controls the enabled state of the menu item - when `false`, the menu item
* will not be clickable and [onClick] will not be invoked
*/
@Composable
fun ColumnScope.OdsDropdownMenuItem(
text: String,
onClick: () -> Unit,
enabled: Boolean = true
) {
DropdownMenuItem(
onClick = onClick,
enabled = enabled
) {
Text(text = text, style = OdsTheme.typography.body1, color = OdsTheme.colors.onSurface)
}
}

/**
* Note: Please use Android Studio preview interactive mode to see the OdsDropdownMenu preview cause expanded is a target state.
*/
@UiModePreviews.Default
@Composable
private fun PreviewOdsDropdownMenu() = Preview {
OdsDropdownMenu(
expanded = true,
onDismissRequest = { },
) {
OdsDropdownMenuItem(
text = "Account",
onClick = { }
)
OdsDropdownMenuItem(
text = "Settings",
onClick = { }
)
}
}