tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit fe454103682c79f627933965fce18f03f7c5a84a
parent 9bf87b6331a3b47aab64fccde05f4a7dd915f6ea
Author: Gabriel Luong <gabriel.luong@gmail.com>
Date:   Fri, 21 Nov 2025 09:03:42 +0000

Bug 1998073 - Part 6: Migrate SavedLoginsScreen to use M3 Acorn color tokens r=android-reviewers,007

- Fixed previews in SavedLoginsScreen to show the LoginsList
- Renamed mozac_ic_filter to mozac_ic_sort_24 to align with the https://github.com/FirefoxUX/acorn-icons/blob/main/icons/mobile/24/xml/ic_sort_24.xml

Top App Bar: https://www.figma.com/design/MjufE1X5fvkxZ0YneX4kRd/Android-Library--2025-?node-id=65138-3594&m=dev
Saved passwords: https://www.figma.com/design/ctk1Pw1TBxUwVgTTOvjHb4/2025-Android-Fundamentals?node-id=972-25884&m=dev

Differential Revision: https://phabricator.services.mozilla.com/D271191

Diffstat:
Dmobile/android/android-components/components/ui/icons/src/main/res/drawable/mozac_ic_filter.xml | 18------------------
Amobile/android/android-components/components/ui/icons/src/main/res/drawable/mozac_ic_sort_24.xml | 12++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/bookmarks/BookmarksScreen.kt | 4++--
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/logins/ui/SavedLoginsScreen.kt | 278++++++++++++++++++++++++++++++++++++-------------------------------------------
4 files changed, 139 insertions(+), 173 deletions(-)

diff --git a/mobile/android/android-components/components/ui/icons/src/main/res/drawable/mozac_ic_filter.xml b/mobile/android/android-components/components/ui/icons/src/main/res/drawable/mozac_ic_filter.xml @@ -1,18 +0,0 @@ -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> -<vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24"> - <path - android:fillColor="@color/mozac_ui_icons_fill" - android:pathData="M3 4.5H21V6.75H3V4.5Z" /> - <path - android:fillColor="@color/mozac_ui_icons_fill" - android:pathData="M5.25 10.5H18.75V12.75H5.25V10.5Z" /> - <path - android:fillColor="@color/mozac_ui_icons_fill" - android:pathData="M14.25 16.5H9.75V18.75H14.25V16.5Z" /> -</vector> diff --git a/mobile/android/android-components/components/ui/icons/src/main/res/drawable/mozac_ic_sort_24.xml b/mobile/android/android-components/components/ui/icons/src/main/res/drawable/mozac_ic_sort_24.xml @@ -0,0 +1,12 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="@color/mozac_ui_icons_fill" + android:pathData="M4,6H20V7.75H4V6ZM6,11.25H18V13H6V11.25ZM10,16.25H14V18H10V16.25Z" /> +</vector> diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/bookmarks/BookmarksScreen.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/bookmarks/BookmarksScreen.kt @@ -794,7 +794,7 @@ private fun BookmarksListTopBarActionsNoSelection( }, ) { Icon( - painter = painterResource(iconsR.drawable.mozac_ic_filter), + painter = painterResource(iconsR.drawable.mozac_ic_sort_24), contentDescription = stringResource( R.string.bookmark_sort_menu_content_desc, ), @@ -1018,7 +1018,7 @@ private fun SelectFolderTopBar(store: BookmarksStore) { store.dispatch(BookmarksListMenuAction.SortMenu.SortMenuButtonClicked) }) { Icon( - painter = painterResource(iconsR.drawable.mozac_ic_filter), + painter = painterResource(iconsR.drawable.mozac_ic_sort_24), contentDescription = stringResource( R.string.bookmark_sort_menu_content_desc, ), diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/logins/ui/SavedLoginsScreen.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/logins/ui/SavedLoginsScreen.kt @@ -5,8 +5,6 @@ package org.mozilla.fenix.settings.logins.ui import androidx.activity.compose.BackHandler -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -22,10 +20,10 @@ import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect @@ -43,6 +41,7 @@ import androidx.compose.ui.semantics.CollectionInfo import androidx.compose.ui.semantics.collectionInfo import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost @@ -53,7 +52,6 @@ import mozilla.components.compose.base.button.IconButton import mozilla.components.compose.base.menu.DropdownMenu import mozilla.components.compose.base.menu.MenuItem import mozilla.components.compose.base.textfield.TextField -import mozilla.components.compose.base.textfield.TextFieldColors import mozilla.components.lib.state.ext.observeAsState import mozilla.components.support.ktx.kotlin.trimmed import org.mozilla.fenix.R @@ -64,6 +62,7 @@ import org.mozilla.fenix.compose.list.SelectableFaviconListItem import org.mozilla.fenix.settings.biometric.ui.SecureScreen import org.mozilla.fenix.settings.logins.ui.LoginsSortOrder.Alphabetical.isGuidToDelete import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.theme.Theme import mozilla.components.ui.icons.R as iconsR /** @@ -133,7 +132,6 @@ private fun LoginsList(store: LoginsStore) { text = state.searchText ?: "", ) }, - containerColor = FirefoxTheme.colors.layer1, contentWindowInsets = WindowInsets(0.dp), ) { paddingValues -> if (state.searchText.isNullOrEmpty() && state.loginItems.isEmpty()) { @@ -156,7 +154,6 @@ private fun LoginsList(store: LoginsStore) { }, ) { itemsIndexed(state.loginItems) { _, item -> - if (state.isGuidToDelete(item.guid)) { return@itemsIndexed } @@ -217,8 +214,8 @@ private fun EmptyList( stringResource(R.string.preferences_passwords_saved_logins_description_empty_text_2), stringResource(R.string.app_name), ), + color = MaterialTheme.colorScheme.onSurfaceVariant, style = FirefoxTheme.typography.body2, - color = FirefoxTheme.colors.textPrimary, ) LinkText( @@ -230,10 +227,6 @@ private fun EmptyList( onClick = { dispatcher(LearnMoreAboutSync) }, ), ), - style = FirefoxTheme.typography.body2.copy( - color = FirefoxTheme.colors.textPrimary, - ), - linkTextColor = FirefoxTheme.colors.textPrimary, linkTextDecoration = TextDecoration.Underline, ) @@ -254,82 +247,73 @@ private fun LoginsListTopBar( var showMenu by remember { mutableStateOf(false) } var searchActive by remember { mutableStateOf(false) } - val iconColor = FirefoxTheme.colors.iconPrimary + TopAppBar( + windowInsets = WindowInsets( + top = 0.dp, + bottom = 0.dp, + ), + title = { + if (!searchActive) { + Text( + text = stringResource(R.string.preferences_passwords_saved_logins_2), + style = FirefoxTheme.typography.headline5, + ) + } else { + SearchBar(text, store) + } + }, + navigationIcon = { + IconButton( + onClick = { + if (!searchActive) { + store.dispatch(LoginsListBackClicked) + } else { + searchActive = false + } + }, + contentDescription = stringResource(R.string.logins_navigate_back_button_content_description), + ) { + Icon( + painter = painterResource(iconsR.drawable.mozac_ic_back_24), + contentDescription = null, + ) + } + }, + actions = { + if (searchActive) return@TopAppBar - Box { - TopAppBar( - colors = TopAppBarDefaults.topAppBarColors(containerColor = FirefoxTheme.colors.layer1), - windowInsets = WindowInsets( - top = 0.dp, - bottom = 0.dp, - ), - title = { - if (!searchActive) { - Text( - color = FirefoxTheme.colors.textPrimary, - style = FirefoxTheme.typography.headline6, - text = stringResource(R.string.preferences_passwords_saved_logins_2), - ) - } else { - SearchBar(text, store) - } - }, - navigationIcon = { + Box { IconButton( onClick = { - if (!searchActive) { - store.dispatch(LoginsListBackClicked) - } else { - searchActive = false - } + showMenu = true }, - contentDescription = null, + contentDescription = stringResource( + R.string.saved_logins_menu_dropdown_chevron_icon_content_description_2, + ), ) { Icon( - painter = painterResource(iconsR.drawable.mozac_ic_back_24), - contentDescription = stringResource(R.string.logins_navigate_back_button_content_description), - tint = iconColor, + painter = painterResource(iconsR.drawable.mozac_ic_sort_24), + contentDescription = null, ) } - }, - actions = { - if (!searchActive) { - Box { - Icon( - modifier = Modifier - .clickable { - showMenu = true - }, - painter = if (showMenu) { - painterResource(R.drawable.ic_chevron_up) - } else { - painterResource(R.drawable.ic_chevron_down) - }, - contentDescription = stringResource( - R.string.saved_logins_menu_dropdown_chevron_icon_content_description_2, - ), - tint = iconColor, - ) - LoginListSortMenu( - showMenu = showMenu, - onDismissRequest = { - showMenu = false - }, - store = store, - ) - } - IconButton(onClick = { searchActive = true }, contentDescription = null) { - Icon( - painter = painterResource(R.drawable.ic_search), - contentDescription = stringResource(R.string.preferences_passwords_saved_logins_search_2), - tint = iconColor, - ) - } - } - }, - ) - } + LoginListSortMenu( + showMenu = showMenu, + onDismissRequest = { + showMenu = false + }, + store = store, + ) + } + + IconButton(onClick = { searchActive = true }, contentDescription = null) { + Icon( + painter = painterResource(iconsR.drawable.mozac_ic_search_24), + contentDescription = stringResource(R.string.preferences_passwords_saved_logins_search_2), + ) + } + }, + ) } private val IconButtonHeight = 48.dp @@ -346,48 +330,40 @@ private fun SearchBar( focusRequester.requestFocus() } - Box { - TextField( - value = text, - placeholder = stringResource(R.string.preferences_passwords_saved_logins_search_2), - onValueChange = { - store.dispatch(SearchLogins(searchText = it, loginItems = store.state.loginItems)) - }, - errorText = "", - modifier = Modifier - .background(color = FirefoxTheme.colors.layer1) - .fillMaxWidth() - .focusRequester(focusRequester), - minHeight = IconButtonHeight, - trailingIcons = { - if (text.isNotBlank()) { - IconButton( - onClick = { - store.dispatch( - SearchLogins( - searchText = "", - loginItems = store.state.loginItems, - ), - ) - }, - contentDescription = null, - ) { - Icon( - painter = painterResource(iconsR.drawable.mozac_ic_cross_24), - contentDescription = null, - tint = FirefoxTheme.colors.iconPrimary, + TextField( + value = text, + placeholder = stringResource(R.string.preferences_passwords_saved_logins_search_2), + onValueChange = { + store.dispatch(SearchLogins(searchText = it, loginItems = store.state.loginItems)) + }, + errorText = "", + modifier = Modifier + .fillMaxWidth() + .focusRequester(focusRequester), + minHeight = IconButtonHeight, + trailingIcons = { + if (text.isNotBlank()) { + IconButton( + onClick = { + store.dispatch( + SearchLogins( + searchText = "", + loginItems = store.state.loginItems, + ), ) - } + }, + contentDescription = null, + ) { + Icon( + painter = painterResource(iconsR.drawable.mozac_ic_cross_24), + contentDescription = null, + ) } - }, - colors = TextFieldColors.default( - placeholderColor = FirefoxTheme.colors.textPrimary, - cursorColor = FirefoxTheme.colors.layerAccent, - ), - keyboardOptions = keyboardOptions, - keyboardActions = keyboardActions, - ) - } + } + }, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + ) } @Composable @@ -420,54 +396,50 @@ private fun LoginListSortMenu( } private const val LOGINS_LIST_SIZE = 15 +private val loginItems = List(LOGINS_LIST_SIZE) { + LoginItem( + guid = "$it", + url = "https://www.justanothersite$it.com", + username = "username $it", + password = "password $it", + ) +} + +private fun createStore() = LoginsStore( + initialState = LoginsState.default.copy( + loginItems = loginItems, + searchText = "", + ), +) @Composable @FlexibleWindowLightDarkPreview private fun LoginsListScreenPreview() { - val loginItems = List(LOGINS_LIST_SIZE) { - LoginItem( - guid = "$it", - url = "https://www.justanothersite$it.com", - username = "username $it", - password = "password $it", - ) - } - - val store = { _: NavHostController -> - LoginsStore( - initialState = LoginsState.default.copy( - loginItems = loginItems, - searchText = "", - ), - ) + FirefoxTheme { + LoginsList(store = createStore()) } +} - FirefoxTheme { - Box(modifier = Modifier.background(color = FirefoxTheme.colors.layer1)) { - SavedLoginsScreen( - buildStore = store, - ) - } +@Composable +@Preview +private fun LoginsListScreenPrivatePreview() { + FirefoxTheme(theme = Theme.Private) { + LoginsList(store = createStore()) } } @Composable @FlexibleWindowLightDarkPreview private fun EmptyLoginsListScreenPreview() { - val store = { _: NavHostController -> - LoginsStore( - initialState = LoginsState.default.copy( - loginItems = listOf(), - searchText = "", - ), - ) + FirefoxTheme { + LoginsList(store = LoginsStore()) } +} - FirefoxTheme { - Box(modifier = Modifier.background(color = FirefoxTheme.colors.layer1)) { - SavedLoginsScreen( - buildStore = store, - ) - } +@Composable +@Preview +private fun EmptyLoginsListScreenPrivatePreview() { + FirefoxTheme(theme = Theme.Private) { + LoginsList(store = LoginsStore()) } }