Skip to content

Commit

Permalink
Iterate design on Settings screen (#1763)
Browse files Browse the repository at this point in the history
* Iterate design on Settings screen:

- Set new icons provided by design.
- Replace `PreferenceText` usages with `ListItem`.
- Add missing icons, and a new way to group them for previews.

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
  • Loading branch information
jmartinesp and ElementBot authored Nov 8, 2023
1 parent b57fddf commit 74e5bf1
Show file tree
Hide file tree
Showing 34 changed files with 208 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fun TimelineItemUnknownView(
TimelineItemInformativeView(
text = stringResource(id = CommonStrings.common_unsupported_event),
iconDescription = stringResource(id = CommonStrings.dialog_title_warning),
iconResourceId = CommonDrawables.ic_compound_info,
iconResourceId = CommonDrawables.ic_compound_info_solid,
extraPadding = extraPadding,
modifier = modifier
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fun TimelineEncryptedHistoryBannerView(
) {
Icon(
modifier = Modifier.size(20.dp),
resourceId = CommonDrawables.ic_compound_info,
resourceId = CommonDrawables.ic_compound_info_solid,
contentDescription = "Info",
tint = ElementTheme.colors.iconInfoPrimary
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,22 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.outlined.InsertChart
import androidx.compose.material.icons.outlined.VerifiedUser
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.features.preferences.impl.user.UserPreferences
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.ListItemStyle
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
Expand Down Expand Up @@ -79,83 +81,86 @@ fun PreferencesRootView(
user = state.myUser,
)
if (state.showCompleteVerification) {
PreferenceText(
title = stringResource(id = CommonStrings.action_complete_verification),
icon = Icons.Outlined.VerifiedUser,
onClick = onVerifyClicked,
ListItem(
headlineContent = { Text(text = stringResource(CommonStrings.common_verify_device)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_check_circle)),
onClick = onVerifyClicked
)
}
if (state.showSecureBackup) {
PreferenceText(
title = stringResource(id = CommonStrings.common_chat_backup),
iconResourceId = CommonDrawables.ic_key_filled,
showEndBadge = state.showSecureBackupBadge,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_chat_backup)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_key_filled),),
trailingContent = ListItemContent.Badge.takeIf { state.showSecureBackupBadge },
onClick = onSecureBackupClicked,
)
}
if (state.showCompleteVerification || state.showSecureBackup) {
HorizontalDivider()
}
if (state.accountManagementUrl != null) {
PreferenceText(
title = stringResource(id = CommonStrings.action_manage_account),
iconResourceId = CommonDrawables.ic_compound_pop_out,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.action_manage_account)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_user)),
trailingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_pop_out)),
onClick = { onManageAccountClicked(state.accountManagementUrl) },
)
HorizontalDivider()
}
if (state.showAnalyticsSettings) {
PreferenceText(
title = stringResource(id = CommonStrings.common_analytics),
icon = Icons.Outlined.InsertChart,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_analytics)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(Icons.Outlined.InsertChart)),
onClick = onOpenAnalytics,
)
}
if (state.showNotificationSettings) {
PreferenceText(
title = stringResource(id = CommonStrings.screen_notification_settings_title),
iconResourceId = CommonDrawables.ic_compound_notifications,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.screen_notification_settings_title)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_notifications)),
onClick = onOpenNotificationSettings,
)
}
PreferenceText(
title = stringResource(id = CommonStrings.action_report_bug),
iconResourceId = CommonDrawables.ic_compound_chat_problem,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_report_a_problem)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_chat_problem)),
onClick = onOpenRageShake
)
PreferenceText(
title = stringResource(id = CommonStrings.common_about),
iconResourceId = CommonDrawables.ic_compound_info,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_about)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_info)),
onClick = onOpenAbout,
)
if (state.showLockScreenSettings) {
PreferenceText(
title = stringResource(id = CommonStrings.common_screen_lock),
icon = Icons.Default.Lock,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_screen_lock)) },
leadingContent = ListItemContent.Icon(IconSource.Vector(Icons.Default.Lock)),
onClick = onOpenLockScreenSettings,
)
}
HorizontalDivider()
if (state.devicesManagementUrl != null) {
PreferenceText(
title = stringResource(id = CommonStrings.action_manage_devices),
iconResourceId = CommonDrawables.ic_compound_pop_out,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.action_manage_devices)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_devices)),
trailingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_pop_out)),
onClick = { onManageAccountClicked(state.devicesManagementUrl) },
)
HorizontalDivider()
}
PreferenceText(
title = stringResource(id = CommonStrings.common_advanced_settings),
iconResourceId = CommonDrawables.ic_compound_settings,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_advanced_settings)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_compound_settings)),
onClick = onOpenAdvancedSettings,
)
if (state.showDeveloperSettings) {
DeveloperPreferencesView(onOpenDeveloperSettings)
}
HorizontalDivider()
PreferenceText(
title = stringResource(id = CommonStrings.action_signout),
iconResourceId = CommonDrawables.ic_compound_leave,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.action_signout)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_sign_out)),
style = ListItemStyle.Destructive,
onClick = onSignOutClicked,
)
Text(
Expand All @@ -172,9 +177,9 @@ fun PreferencesRootView(

@Composable
private fun DeveloperPreferencesView(onOpenDeveloperSettings: () -> Unit) {
PreferenceText(
title = stringResource(id = CommonStrings.common_developer_options),
iconResourceId = CommonDrawables.ic_developer_mode,
ListItem(
headlineContent = { Text(stringResource(id = CommonStrings.common_developer_options)) },
leadingContent = ListItemContent.Icon(IconSource.Resource(CommonDrawables.ic_developer_options)),
onClick = onOpenDeveloperSettings
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ private fun RecoveryKeyFooter(state: RecoveryKeyViewState) {
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
resourceId = CommonDrawables.ic_compound_info,
resourceId = CommonDrawables.ic_compound_info_solid,
contentDescription = null,
tint = ElementTheme.colors.iconSecondary,
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,25 @@ internal fun InfoListItemMoleculePreview() {
) {
InfoListItemMolecule(
message = { Text("A single item") },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info, contentDescription = null) },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info_solid, contentDescription = null) },
position = InfoListItemPosition.Single,
backgroundColor = color,
)
InfoListItemMolecule(
message = { Text("A top item") },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info, contentDescription = null) },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info_solid, contentDescription = null) },
position = InfoListItemPosition.Top,
backgroundColor = color,
)
InfoListItemMolecule(
message = { Text("A middle item") },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info, contentDescription = null) },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info_solid, contentDescription = null) },
position = InfoListItemPosition.Middle,
backgroundColor = color,
)
InfoListItemMolecule(
message = { Text("A bottom item") },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info, contentDescription = null) },
icon = { Icon(resourceId = CommonDrawables.ic_compound_info_solid, contentDescription = null) },
position = InfoListItemPosition.Bottom,
backgroundColor = color,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.atomic.atoms.RedIndicatorAtom
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.Checkbox as CheckboxComponent
Expand Down Expand Up @@ -94,6 +95,9 @@ sealed interface ListItemContent {
/** Displays any custom content. */
data class Custom(val content: @Composable () -> Unit) : ListItemContent

/** Displays a badge. */
data object Badge : ListItemContent

@Composable
fun View() {
when (this) {
Expand All @@ -114,12 +118,15 @@ sealed interface ListItemContent {
onClick = onClick,
enabled = enabled
)
is Icon -> IconComponent(
modifier = Modifier.size(maxCompactSize),
painter = iconSource.getPainter(),
contentDescription = iconSource.contentDescription
)
is Icon -> {
IconComponent(
modifier = Modifier.size(maxCompactSize),
painter = iconSource.getPainter(),
contentDescription = iconSource.contentDescription
)
}
is Text -> TextComponent(modifier = Modifier.widthIn(max = 128.dp), text = text, maxLines = 1, overflow = TextOverflow.Ellipsis)
is Badge -> RedIndicatorAtom()
is Custom -> content()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal val iconsCompound = listOf(
R.drawable.ic_compound_chat_problem,
R.drawable.ic_compound_check,
R.drawable.ic_compound_check_circle,
R.drawable.ic_compound_check_circle_solid,
R.drawable.ic_compound_chevron_down,
R.drawable.ic_compound_chevron_left,
R.drawable.ic_compound_chevron_right,
Expand All @@ -48,6 +49,7 @@ internal val iconsCompound = listOf(
R.drawable.ic_compound_filter,
R.drawable.ic_compound_grid_view,
R.drawable.ic_compound_info,
R.drawable.ic_compound_info_solid,
R.drawable.ic_compound_leave,
R.drawable.ic_compound_link,
R.drawable.ic_compound_lock,
Expand Down Expand Up @@ -79,6 +81,7 @@ internal val iconsCompound = listOf(
R.drawable.ic_compound_spotlight_view,
R.drawable.ic_compound_threads,
R.drawable.ic_compound_threads_solid,
R.drawable.ic_compound_user,
R.drawable.ic_compound_user_add,
R.drawable.ic_compound_user_add_solid,
R.drawable.ic_compound_user_profile,
Expand Down Expand Up @@ -116,7 +119,8 @@ internal val iconsSeptember = listOf(
// This list and all the drawable it contains should be removed at some point.
// All the icons should be defined in Compound.
internal val iconsOther = listOf(
R.drawable.ic_developer_mode,
R.drawable.ic_developer_options,
R.drawable.ic_devices,
R.drawable.ic_groups,
R.drawable.ic_indent_decrease,
R.drawable.ic_indent_increase,
Expand All @@ -130,4 +134,5 @@ internal val iconsOther = listOf(
R.drawable.ic_strikethrough,
R.drawable.ic_thread_decoration,
R.drawable.ic_underline,
R.drawable.ic_sign_out,
)
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,40 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toPersistentList

@PreviewsDayNight
@Composable
internal fun IconsCompoundPart1Preview() = ElementPreview {
IconsPreview(
title = "R.drawable.ic_compound_* 1 / 2",
iconsList = iconsCompound.take(36).toPersistentList(),
iconNameTransform = { name ->
name.removePrefix("ic_compound_")
.replace("_", " ")
})
internal class IconChunkPreviewProvider : PreviewParameterProvider<IconChunk> {
override val values: Sequence<IconChunk>
get() {
val chunks = iconsCompound.chunked(36)
return chunks.mapIndexed { index, chunk ->
IconChunk(index = index+1, total = chunks.size, icons = chunk.toPersistentList())
}
.asSequence()
}
}

internal data class IconChunk(
val index: Int,
val total: Int,
val icons: ImmutableList<Int>,
)

@PreviewsDayNight
@Composable
internal fun IconsCompoundPart2Preview() = ElementPreview {
internal fun IconsCompoundPreview(@PreviewParameter(IconChunkPreviewProvider::class) chunk: IconChunk) = ElementPreview {
IconsPreview(
title = "R.drawable.ic_compound_* 2 / 2",
iconsList = iconsCompound.drop(36).toPersistentList(),
title = "R.drawable.ic_compound_* ${chunk.index}/${chunk.total}",
iconsList = chunk.icons,
iconNameTransform = { name ->
name.removePrefix("ic_compound_")
.replace("_", " ")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
<!--
~ Copyright (c) 2023 New Vector Ltd
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M10.6,13.8L8.45,11.65C8.267,11.467 8.033,11.375 7.75,11.375C7.467,11.375 7.233,11.467 7.05,11.65C6.867,11.833 6.775,12.067 6.775,12.35C6.775,12.633 6.867,12.867 7.05,13.05L9.9,15.9C10.1,16.1 10.333,16.2 10.6,16.2C10.867,16.2 11.1,16.1 11.3,15.9L16.95,10.25C17.133,10.067 17.225,9.833 17.225,9.55C17.225,9.267 17.133,9.033 16.95,8.85C16.767,8.667 16.533,8.575 16.25,8.575C15.967,8.575 15.733,8.667 15.55,8.85L10.6,13.8ZM12,22C10.617,22 9.317,21.737 8.1,21.212C6.883,20.688 5.825,19.975 4.925,19.075C4.025,18.175 3.313,17.117 2.787,15.9C2.263,14.683 2,13.383 2,12C2,10.617 2.263,9.317 2.787,8.1C3.313,6.883 4.025,5.825 4.925,4.925C5.825,4.025 6.883,3.313 8.1,2.787C9.317,2.263 10.617,2 12,2C13.383,2 14.683,2.263 15.9,2.787C17.117,3.313 18.175,4.025 19.075,4.925C19.975,5.825 20.688,6.883 21.212,8.1C21.737,9.317 22,10.617 22,12C22,13.383 21.737,14.683 21.212,15.9C20.688,17.117 19.975,18.175 19.075,19.075C18.175,19.975 17.117,20.688 15.9,21.212C14.683,21.737 13.383,22 12,22Z"
android:fillColor="@android:color/white"/>
<path
android:fillColor="#FF000000"
android:pathData="M10.6 13.8l-2.2-2.2c-0.2-0.2-0.4-0.3-0.7-0.3-0.3 0-0.5 0.1-0.7 0.3-0.2 0.2-0.3 0.4-0.3 0.7 0 0.3 0.1 0.5 0.3 0.7L9.9 15.9c0.2 0.2 0.4 0.3 0.7 0.3 0.3 0 0.5-0.1 0.7-0.3l5.7-5.7c0.2-0.2 0.3-0.4 0.3-0.7 0-0.3-0.1-0.5-0.3-0.7-0.2-0.2-0.4-0.3-0.7-0.3-0.3 0-0.5 0.1-0.7 0.3L10.6 13.8ZM12 22c-1.4 0-2.7-0.3-3.9-0.8-1.2-0.5-2.3-1.2-3.2-2.1-0.9-0.9-1.6-2-2.1-3.2C2.3 14.7 2 13.4 2 12s0.3-2.7 0.8-3.9C3.3 6.9 4 5.8 4.9 4.9c0.9-0.9 2-1.6 3.2-2.1C9.3 2.3 10.6 2 12 2s2.7 0.3 3.9 0.8c1.2 0.5 2.3 1.2 3.2 2.1 0.9 0.9 1.6 2 2.1 3.2C21.7 9.3 22 10.6 22 12s-0.3 2.7-0.8 3.9c-0.5 1.2-1.2 2.3-2.1 3.2-0.9 0.9-2 1.6-3.2 2.1C14.7 21.7 13.4 22 12 22Zm0-2c2.2 0 4.1-0.8 5.7-2.3C19.2 16.1 20 14.2 20 12c0-2.2-0.8-4.1-2.3-5.7C16.1 4.8 14.2 4 12 4 9.8 4 7.9 4.8 6.3 6.3 4.8 7.9 4 9.8 4 12s0.8 4.1 2.3 5.7C7.9 19.2 9.8 20 12 20Z"/>
</vector>
Loading

0 comments on commit 74e5bf1

Please sign in to comment.