From c963e99dca76d8d334c7dfbf0d062305daebfaa2 Mon Sep 17 00:00:00 2001 From: Nicholas Date: Thu, 18 May 2023 19:02:05 -0400 Subject: [PATCH] Introduce the ability to change the app icon. --- app/src/main/AndroidManifest.xml | 301 +++++++++++++++++ .../appearance/AppearanceSettingsFragment.kt | 10 + .../appicon/AppIconSelectionFragment.kt | 306 ++++++++++++++++++ .../appicon/AppIconTutorialFragment.kt | 119 +++++++ .../appearance/appicon/util/AppIconPreset.kt | 32 ++ .../appearance/appicon/util/AppIconUtility.kt | 58 ++++ .../securesms/util/ConversationUtil.java | 13 +- .../app_icon_tutorial_apps_homescreen.xml | 204 ++++++++++++ .../app_icon_tutorial_notification.xml | 55 ++++ .../ic_app_icon_bubbles_top_preview.xml | 55 ++++ .../drawable/ic_app_icon_chat_top_preview.xml | 30 ++ .../ic_app_icon_default_top_preview.xml | 12 + .../drawable/ic_app_icon_news_top_preview.xml | 33 ++ .../ic_app_icon_notes_top_preview.xml | 54 ++++ .../ic_app_icon_signal_color_top_preview.xml | 35 ++ .../ic_app_icon_signal_dark_top_preview.xml | 32 ++ ...p_icon_signal_dark_variant_top_preview.xml | 32 ++ ...ic_app_icon_signal_default_top_preview.xml | 9 + .../ic_app_icon_signal_white_top_preview.xml | 30 ++ .../ic_app_icon_waves_top_preview.xml | 36 +++ .../ic_app_icon_weather_top_preview.xml | 111 +++++++ .../ic_app_icon_yellow_top_preview.xml | 123 +++++++ .../ic_launcher_alt_bubbles_background.xml | 9 + .../ic_launcher_alt_bubbles_foreground.xml | 51 +++ .../ic_launcher_alt_bubbles_monochrome.xml | 19 ++ .../ic_launcher_alt_chat_background.xml | 24 ++ .../ic_launcher_alt_chat_foreground.xml | 16 + .../ic_launcher_alt_chat_monochrome.xml | 16 + .../ic_launcher_alt_news_background.xml | 9 + .../ic_launcher_alt_news_foreground.xml | 36 +++ .../ic_launcher_alt_news_monochrome.xml | 22 ++ .../ic_launcher_alt_notes_background.xml | 9 + .../ic_launcher_alt_notes_foreground.xml | 57 ++++ .../ic_launcher_alt_notes_monochrome.xml | 25 ++ ...c_launcher_alt_signal_color_background.xml | 31 ++ ...c_launcher_alt_signal_color_foreground.xml | 16 + ...ic_launcher_alt_signal_dark_background.xml | 14 + ...ic_launcher_alt_signal_dark_foreground.xml | 33 ++ ...her_alt_signal_dark_variant_background.xml | 14 + ...her_alt_signal_dark_variant_foreground.xml | 33 ++ ...c_launcher_alt_signal_white_background.xml | 11 + ...c_launcher_alt_signal_white_foreground.xml | 31 ++ .../ic_launcher_alt_waves_background.xml | 25 ++ .../ic_launcher_alt_waves_foreground.xml | 22 ++ .../ic_launcher_alt_waves_monochrome.xml | 16 + .../ic_launcher_alt_weather_background.xml | 25 ++ .../ic_launcher_alt_weather_foreground.xml | 99 ++++++ .../ic_launcher_alt_weather_monochrome.xml | 28 ++ .../ic_launcher_alt_yellow_background.xml | 104 ++++++ .../ic_launcher_alt_yellow_foreground.xml | 17 + .../ic_launcher_alt_yellow_monochrome.xml | 16 + .../res/drawable/ic_launcher_foreground.xml | 2 +- .../res/drawable/ic_launcher_monochrome.xml | 92 +++--- .../res/layout/activity_app_icon_settings.xml | 11 + .../ic_launcher_alt_bubbles.xml | 6 + .../ic_launcher_alt_chat.xml | 6 + .../ic_launcher_alt_news.xml | 6 + .../ic_launcher_alt_notes.xml | 6 + .../ic_launcher_alt_signal_color.xml | 6 + .../ic_launcher_alt_signal_dark.xml | 6 + .../ic_launcher_alt_signal_dark_variant.xml | 6 + .../ic_launcher_alt_signal_white.xml | 6 + .../ic_launcher_alt_waves.xml | 6 + .../ic_launcher_alt_weather.xml | 6 + .../ic_launcher_alt_yellow.xml | 6 + app/src/main/res/navigation/app_settings.xml | 27 ++ app/src/main/res/values/strings.xml | 31 ++ 67 files changed, 2697 insertions(+), 50 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconSelectionFragment.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconTutorialFragment.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconPreset.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconUtility.kt create mode 100644 app/src/main/res/drawable/app_icon_tutorial_apps_homescreen.xml create mode 100644 app/src/main/res/drawable/app_icon_tutorial_notification.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_bubbles_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_chat_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_default_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_news_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_notes_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_signal_color_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_signal_dark_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_signal_dark_variant_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_signal_default_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_signal_white_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_waves_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_weather_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_app_icon_yellow_top_preview.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_bubbles_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_bubbles_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_bubbles_monochrome.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_chat_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_chat_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_chat_monochrome.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_news_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_news_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_news_monochrome.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_notes_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_notes_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_notes_monochrome.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_color_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_color_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_dark_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_dark_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_white_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_signal_white_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_waves_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_waves_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_waves_monochrome.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_weather_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_weather_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_weather_monochrome.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_yellow_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_yellow_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_alt_yellow_monochrome.xml create mode 100644 app/src/main/res/layout/activity_app_icon_settings.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_bubbles.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_chat.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_news.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_notes.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_color.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark_variant.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_white.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_waves.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_weather.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_yellow.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1af49c35dd..282d8854f0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -257,6 +257,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + = 26) { + clickPref( + title = DSLSettingsText.from(R.string.preferences__app_icon), + onClick = { + Navigation.findNavController(requireView()).safeNavigate(R.id.action_appearanceSettings_to_appIconActivity) + } + ) + } + radioListPref( title = DSLSettingsText.from(R.string.preferences_chats__message_text_size), listItems = messageFontSizeLabels, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconSelectionFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconSelectionFragment.kt new file mode 100644 index 0000000000..71e67001e4 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconSelectionFragment.kt @@ -0,0 +1,306 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.settings.app.appearance.appicon + +import android.content.Context +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.Image +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.text.ClickableText +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +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.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.navigation.fragment.findNavController +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList +import org.signal.core.ui.Scaffolds +import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.settings.app.appearance.appicon.util.AppIconPreset +import org.thoughtcrime.securesms.components.settings.app.appearance.appicon.util.AppIconUtility +import org.thoughtcrime.securesms.compose.ComposeFragment +import org.thoughtcrime.securesms.util.navigation.safeNavigate + +class AppIconSelectionFragment : ComposeFragment() { + private lateinit var appIconUtility: AppIconUtility + + override fun onAttach(context: Context) { + super.onAttach(context) + appIconUtility = AppIconUtility(context) + } + + @Composable + override fun FragmentContent() { + Scaffolds.Settings( + title = stringResource(id = R.string.preferences__app_icon), + onNavigationClick = { + findNavController().popBackStack() + }, + navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24), + navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close) + ) { contentPadding: PaddingValues -> + IconSelectionScreen(appIconUtility.currentAppIcon, ::updateAppIcon, ::openLearnMore, Modifier.padding(contentPadding)) + } + } + + private fun updateAppIcon(preset: AppIconPreset) { + if (!appIconUtility.isCurrentlySelected(preset)) { + appIconUtility.setNewAppIcon(preset) + } + } + + private fun openLearnMore() { + findNavController().safeNavigate(R.id.action_appIconSelectionFragment_to_appIconTutorialFragment) + } + + /** + * Screen allowing the user to view all the possible icon and select a new one to use. + */ + @Composable + fun IconSelectionScreen(activeIcon: AppIconPreset, onItemConfirmed: (AppIconPreset) -> Unit, onWarningClick: () -> Unit, modifier: Modifier = Modifier) { + var showDialog: Boolean by remember { mutableStateOf(false) } + var pendingIcon: AppIconPreset by remember { + mutableStateOf(activeIcon) + } + + if (showDialog) { + ChangeIconDialog( + pendingIcon = pendingIcon, + onConfirm = { + onItemConfirmed(pendingIcon) + showDialog = false + }, + onDismiss = { + pendingIcon = activeIcon + showDialog = false + } + ) + } + + Column(modifier = modifier.verticalScroll(rememberScrollState())) { + Spacer(modifier = Modifier.size(12.dp)) + CaveatWarning( + onClick = onWarningClick, + modifier = Modifier.padding(horizontal = 24.dp) + ) + Spacer(modifier = Modifier.size(12.dp)) + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 18.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + enumValues().toList().chunked(COLUMN_COUNT).map { it.toImmutableList() }.forEach { items -> + IconRow( + presets = items, + isSelected = { it == pendingIcon }, + onItemClick = { + pendingIcon = it + showDialog = true + } + ) + } + } + } + } + + @Composable + fun ChangeIconDialog(pendingIcon: AppIconPreset, onConfirm: () -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier) { + AlertDialog( + modifier = modifier, + onDismissRequest = onDismiss, + confirmButton = { + TextButton( + onClick = onConfirm + ) { + Text(text = stringResource(id = R.string.preferences__app_icon_dialog_ok)) + } + }, + dismissButton = { + TextButton( + onClick = onDismiss + ) { + Text(text = stringResource(id = R.string.preferences__app_icon_dialog_cancel)) + } + }, + icon = { + AppIcon(preset = pendingIcon, isSelected = false, onClick = {}) + }, + title = { + Text( + text = stringResource(id = R.string.preferences__app_icon_dialog_title, stringResource(id = pendingIcon.labelResId)), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.headlineSmall + ) + }, + text = { + Text( + text = stringResource(id = R.string.preferences__app_icon_dialog_description), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyMedium + ) + } + ) + } + + /** + * Composable rendering the one row of icons that the user may choose from. + */ + @Composable + fun IconRow(presets: ImmutableList, isSelected: (AppIconPreset) -> Boolean, onItemClick: (AppIconPreset) -> Unit, modifier: Modifier = Modifier) { + Row(modifier = modifier.fillMaxWidth()) { + presets.forEach { preset -> + val currentlySelected = isSelected(preset) + IconGridElement( + preset = preset, + isSelected = currentlySelected, + onClickHandler = { + if (!currentlySelected) { + onItemClick(preset) + } + }, + modifier = Modifier + .padding(vertical = 18.dp) + .weight(1f) + ) + } + } + } + + /** + * Composable rendering an individual icon inside that grid, including the black border of the selected icon. + */ + @Composable + fun IconGridElement(preset: AppIconPreset, isSelected: Boolean, onClickHandler: () -> Unit, modifier: Modifier = Modifier) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + val boxModifier = Modifier.size(64.dp) + Box( + modifier = if (isSelected) boxModifier.border(3.dp, MaterialTheme.colorScheme.onBackground, CircleShape) else boxModifier + ) { + AppIcon(preset = preset, isSelected = isSelected, onClickHandler, modifier = Modifier.align(Alignment.Center)) + } + Spacer(modifier = Modifier.size(8.dp)) + Text( + text = stringResource(id = preset.labelResId), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + /** + * Composable rendering the multiple layers of an adaptive icon onto one flattened rasterized Canvas. + */ + @Composable + fun AppIcon(preset: AppIconPreset, isSelected: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) { + val bitmapSize: Dp = if (isSelected) 48.dp else 64.dp + val imageModifier = modifier + .size(bitmapSize) + .graphicsLayer( + shape = CircleShape, + shadowElevation = if (isSelected) 4f else 8f, + clip = true + ) + .clickable(onClick = onClick) + Image( + painterResource(id = preset.iconPreviewResId), + contentDescription = stringResource(id = preset.labelResId), + modifier = imageModifier + ) + } + + /** + * A clickable "learn more" block of text. + */ + @Composable + fun CaveatWarning(onClick: () -> Unit, modifier: Modifier = Modifier) { + val learnMoreString = stringResource(R.string.preferences__app_icon_learn_more) + val completeString = stringResource(R.string.preferences__app_icon_warning_learn_more) + val learnMoreStartIndex = completeString.indexOf(learnMoreString).coerceAtLeast(0) + val learnMoreEndIndex = learnMoreStartIndex + learnMoreString.length + val doesStringEndWithLearnMore = learnMoreEndIndex >= completeString.lastIndex + val annotatedText = buildAnnotatedString { + withStyle( + style = SpanStyle( + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + ) { + append(completeString.substring(0, learnMoreStartIndex)) + } + pushStringAnnotation( + tag = URL_TAG, + annotation = LEARN_MORE_TAG + ) + withStyle( + style = SpanStyle( + color = MaterialTheme.colorScheme.primary + ) + ) { + append(learnMoreString) + } + pop() + if (!doesStringEndWithLearnMore) { + append(completeString.substring(learnMoreEndIndex, completeString.lastIndex)) + } + } + ClickableText( + text = annotatedText, + onClick = { _ -> + onClick() + }, + style = MaterialTheme.typography.bodyMedium, + modifier = modifier + ) + } + + @Preview + @Composable + private fun MainScreenPreview() { + IconSelectionScreen(AppIconPreset.DEFAULT, onItemConfirmed = {}, onWarningClick = {}) + } + + companion object { + val TAG = Log.tag(AppIconSelectionFragment::class.java) + + private const val LEARN_MORE_TAG = "learn_more" + private const val URL_TAG = "URL" + private const val COLUMN_COUNT = 4 + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconTutorialFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconTutorialFragment.kt new file mode 100644 index 0000000000..28e4b8686c --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/AppIconTutorialFragment.kt @@ -0,0 +1,119 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.settings.app.appearance.appicon + +import androidx.compose.foundation.Image +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.navigation.fragment.findNavController +import org.signal.core.ui.Scaffolds +import org.signal.core.util.logging.Log +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.compose.ComposeFragment + +class AppIconTutorialFragment : ComposeFragment() { + + @Composable + override fun FragmentContent() { + Scaffolds.Settings( + title = "", + onNavigationClick = { + findNavController().popBackStack() + }, + navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24), + navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close) + ) { contentPadding: PaddingValues -> + TutorialScreen(Modifier.padding(contentPadding)) + } + } + + @Composable + fun TutorialScreen(modifier: Modifier = Modifier) { + Box(modifier = modifier) { + Column( + modifier = Modifier + .padding(horizontal = 24.dp) + .align(Alignment.Center) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + val borderShape = RoundedCornerShape(12.dp) + + Text( + text = stringResource(R.string.preferences__app_icon_warning), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(vertical = 20.dp) + ) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .clip(borderShape) + .border(1.dp, MaterialTheme.colorScheme.outline, shape = borderShape) + ) { + Image( + painter = painterResource(R.drawable.app_icon_tutorial_apps_homescreen), + contentDescription = stringResource(R.string.preferences__graphic_illustrating_where_the_replacement_app_icon_will_be_visible), + contentScale = ContentScale.FillWidth, + modifier = Modifier + .widthIn(max = 328.dp) + ) + } + Text( + text = stringResource(id = R.string.preferences__app_icon_notification_warning), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(vertical = 20.dp) + ) + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .clip(borderShape) + .border(1.dp, MaterialTheme.colorScheme.outline, shape = borderShape) + ) { + Image( + painter = painterResource(R.drawable.app_icon_tutorial_notification), + contentDescription = stringResource(R.string.preferences__graphic_illustrating_where_the_replacement_app_icon_will_be_visible), + contentScale = ContentScale.FillWidth, + modifier = Modifier + .widthIn(max = 328.dp) + ) + } + } + } + } + + @Preview + @Composable + private fun TutorialScreenPreview() { + TutorialScreen() + } + + companion object { + val TAG = Log.tag(AppIconTutorialFragment::class.java) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconPreset.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconPreset.kt new file mode 100644 index 0000000000..145455e2cc --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconPreset.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.settings.app.appearance.appicon.util + +import android.content.ComponentName +import android.content.Context +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import org.thoughtcrime.securesms.R + +enum class AppIconPreset(private val componentName: String, @DrawableRes val iconPreviewResId: Int, @StringRes val labelResId: Int) { + DEFAULT(".RoutingActivity", R.drawable.ic_app_icon_default_top_preview, R.string.app_name), + WHITE(".RoutingActivityAltWhite", R.drawable.ic_app_icon_signal_white_top_preview, R.string.app_name), + COLOR(".RoutingActivityAltColor", R.drawable.ic_app_icon_signal_color_top_preview, R.string.app_name), + DARK(".RoutingActivityAltDark", R.drawable.ic_app_icon_signal_dark_top_preview, R.string.app_name), + DARK_VARIANT(".RoutingActivityAltDarkVariant", R.drawable.ic_app_icon_signal_dark_variant_top_preview, R.string.app_name), + CHAT(".RoutingActivityAltChat", R.drawable.ic_app_icon_chat_top_preview, R.string.app_name), + BUBBLES(".RoutingActivityAltBubbles", R.drawable.ic_app_icon_bubbles_top_preview, R.string.app_name), + YELLOW(".RoutingActivityAltYellow", R.drawable.ic_app_icon_yellow_top_preview, R.string.app_name), + NEWS(".RoutingActivityAltNews", R.drawable.ic_app_icon_news_top_preview, R.string.app_icon_label_news), + NOTES(".RoutingActivityAltNotes", R.drawable.ic_app_icon_notes_top_preview, R.string.app_icon_label_notes), + WEATHER(".RoutingActivityAltWeather", R.drawable.ic_app_icon_weather_top_preview, R.string.app_icon_label_weather), + WAVES(".RoutingActivityAltWaves", R.drawable.ic_app_icon_waves_top_preview, R.string.app_icon_label_waves); + + fun getComponentName(context: Context): ComponentName { + val applicationContext = context.applicationContext + return ComponentName(applicationContext, applicationContext.packageName + componentName) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconUtility.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconUtility.kt new file mode 100644 index 0000000000..7598db44ba --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/appicon/util/AppIconUtility.kt @@ -0,0 +1,58 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.components.settings.app.appearance.appicon.util + +import android.content.ComponentName +import android.content.Context +import android.content.pm.PackageManager +import org.signal.core.util.logging.Log + +class AppIconUtility(context: Context) { + private val applicationContext: Context = context.applicationContext + private val pm = applicationContext.packageManager + + val currentAppIcon by lazy { readCurrentAppIconFromPackageManager() } + + fun isCurrentlySelected(preset: AppIconPreset): Boolean { + return preset == currentAppIcon + } + + fun currentAppIconComponentName(): ComponentName { + return currentAppIcon.getComponentName(applicationContext) ?: AppIconPreset.DEFAULT.getComponentName(applicationContext) + } + + fun setNewAppIcon(desiredAppIcon: AppIconPreset) { + currentAppIcon.let { + pm.setComponentEnabledSetting(it.getComponentName(applicationContext), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP) + } + pm.setComponentEnabledSetting(desiredAppIcon.getComponentName(applicationContext), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP) + } + + private fun readCurrentAppIconFromPackageManager(): AppIconPreset { + val activeIcon = enumValues().firstOrNull { + val componentName = it.getComponentName(applicationContext) + val componentEnabledSetting = pm.getComponentEnabledSetting(componentName) + + Log.d(TAG, "Found $componentName with state of $componentEnabledSetting") + if (it == AppIconPreset.DEFAULT && componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) { + return it + } + + componentEnabledSetting == PackageManager.COMPONENT_ENABLED_STATE_ENABLED + } + + return if (activeIcon == null) { + setNewAppIcon(AppIconPreset.DEFAULT) + AppIconPreset.DEFAULT + } else { + activeIcon + } + } + + companion object { + private const val TAG = "AppIconUtility" + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java index 42e8752a40..4f7f5dc0e6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ConversationUtil.java @@ -17,6 +17,7 @@ import com.google.common.collect.Sets; import org.signal.core.util.concurrent.SignalExecutors; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.components.settings.app.appearance.appicon.util.AppIconUtility; import org.thoughtcrime.securesms.conversation.ConversationIntents; import org.thoughtcrime.securesms.database.GroupTable; import org.thoughtcrime.securesms.database.SignalDatabase; @@ -173,8 +174,10 @@ public final class ConversationUtil { List shortcuts = new ArrayList<>(rankedRecipients.size()); + ComponentName activityName = new AppIconUtility(context).currentAppIconComponentName(); + for (int i = 0; i < rankedRecipients.size(); i++) { - ShortcutInfoCompat info = buildShortcutInfo(context, rankedRecipients.get(i), i, Direction.NONE); + ShortcutInfoCompat info = buildShortcutInfo(context, activityName, rankedRecipients.get(i), i, Direction.NONE); shortcuts.add(info); } @@ -188,7 +191,10 @@ public final class ConversationUtil { */ @WorkerThread private static boolean pushShortcutForRecipientInternal(@NonNull Context context, @NonNull Recipient recipient, int rank, @NonNull Direction direction) { - ShortcutInfoCompat shortcutInfo = buildShortcutInfo(context, recipient, rank, direction); + + ComponentName activityName = new AppIconUtility(context).currentAppIconComponentName(); + + ShortcutInfoCompat shortcutInfo = buildShortcutInfo(context, activityName, recipient, rank, direction); return ShortcutManagerCompat.pushDynamicShortcut(context, shortcutInfo); } @@ -203,6 +209,7 @@ public final class ConversationUtil { */ @WorkerThread private static @NonNull ShortcutInfoCompat buildShortcutInfo(@NonNull Context context, + @NonNull ComponentName activity, @NonNull Recipient recipient, int rank, @NonNull Direction direction) @@ -222,7 +229,7 @@ public final class ConversationUtil { .setIcon(AvatarUtil.getIconCompatForShortcut(context, resolved)) .setPersons(persons) .setCategories(Sets.newHashSet(CATEGORY_SHARE_TARGET)) - .setActivity(new ComponentName(context, "org.thoughtcrime.securesms.RoutingActivity")) + .setActivity(activity) .setRank(rank) .setLocusId(new LocusIdCompat(shortcutId)); diff --git a/app/src/main/res/drawable/app_icon_tutorial_apps_homescreen.xml b/app/src/main/res/drawable/app_icon_tutorial_apps_homescreen.xml new file mode 100644 index 0000000000..94da2823a7 --- /dev/null +++ b/app/src/main/res/drawable/app_icon_tutorial_apps_homescreen.xml @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/app_icon_tutorial_notification.xml b/app/src/main/res/drawable/app_icon_tutorial_notification.xml new file mode 100644 index 0000000000..64c94da98e --- /dev/null +++ b/app/src/main/res/drawable/app_icon_tutorial_notification.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_bubbles_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_bubbles_top_preview.xml new file mode 100644 index 0000000000..80795c454f --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_bubbles_top_preview.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_chat_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_chat_top_preview.xml new file mode 100644 index 0000000000..b35efd30a4 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_chat_top_preview.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_default_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_default_top_preview.xml new file mode 100644 index 0000000000..0f6ff2eb05 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_default_top_preview.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_news_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_news_top_preview.xml new file mode 100644 index 0000000000..9cc1ae4881 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_news_top_preview.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_notes_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_notes_top_preview.xml new file mode 100644 index 0000000000..11b1e420da --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_notes_top_preview.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_signal_color_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_signal_color_top_preview.xml new file mode 100644 index 0000000000..54264ce8d0 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_signal_color_top_preview.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_signal_dark_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_signal_dark_top_preview.xml new file mode 100644 index 0000000000..23be53fe3a --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_signal_dark_top_preview.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_signal_dark_variant_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_signal_dark_variant_top_preview.xml new file mode 100644 index 0000000000..2d4267b7ab --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_signal_dark_variant_top_preview.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_signal_default_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_signal_default_top_preview.xml new file mode 100644 index 0000000000..b2d822b2f8 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_signal_default_top_preview.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_app_icon_signal_white_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_signal_white_top_preview.xml new file mode 100644 index 0000000000..08298b4a75 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_signal_white_top_preview.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_waves_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_waves_top_preview.xml new file mode 100644 index 0000000000..79fcddab50 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_waves_top_preview.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_weather_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_weather_top_preview.xml new file mode 100644 index 0000000000..d2635dcd16 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_weather_top_preview.xml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_app_icon_yellow_top_preview.xml b/app/src/main/res/drawable/ic_app_icon_yellow_top_preview.xml new file mode 100644 index 0000000000..29d5b9dcd1 --- /dev/null +++ b/app/src/main/res/drawable/ic_app_icon_yellow_top_preview.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_bubbles_background.xml b/app/src/main/res/drawable/ic_launcher_alt_bubbles_background.xml new file mode 100644 index 0000000000..16ac8107eb --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_bubbles_background.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_bubbles_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_bubbles_foreground.xml new file mode 100644 index 0000000000..9b2b48d277 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_bubbles_foreground.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_bubbles_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_bubbles_monochrome.xml new file mode 100644 index 0000000000..b0849b5584 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_bubbles_monochrome.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_chat_background.xml b/app/src/main/res/drawable/ic_launcher_alt_chat_background.xml new file mode 100644 index 0000000000..cda1a5ab3f --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_chat_background.xml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_chat_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_chat_foreground.xml new file mode 100644 index 0000000000..fa2ab7db41 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_chat_foreground.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_chat_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_chat_monochrome.xml new file mode 100644 index 0000000000..ebf5ec2ebb --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_chat_monochrome.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_news_background.xml b/app/src/main/res/drawable/ic_launcher_alt_news_background.xml new file mode 100644 index 0000000000..5bfd27384d --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_news_background.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_news_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_news_foreground.xml new file mode 100644 index 0000000000..f6bd7cd284 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_news_foreground.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_news_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_news_monochrome.xml new file mode 100644 index 0000000000..31bd93800f --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_news_monochrome.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_notes_background.xml b/app/src/main/res/drawable/ic_launcher_alt_notes_background.xml new file mode 100644 index 0000000000..1c2abe0c8b --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_notes_background.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_notes_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_notes_foreground.xml new file mode 100644 index 0000000000..07b8e13bcd --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_notes_foreground.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_notes_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_notes_monochrome.xml new file mode 100644 index 0000000000..f1dbbc47f4 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_notes_monochrome.xml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_color_background.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_color_background.xml new file mode 100644 index 0000000000..4587126d03 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_color_background.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_color_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_color_foreground.xml new file mode 100644 index 0000000000..18df352373 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_color_foreground.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_dark_background.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_background.xml new file mode 100644 index 0000000000..92bd06366b --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_background.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_dark_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_foreground.xml new file mode 100644 index 0000000000..ba5e0f3e3b --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_foreground.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_background.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_background.xml new file mode 100644 index 0000000000..5bb7f7ad86 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_background.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_foreground.xml new file mode 100644 index 0000000000..f103504179 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_dark_variant_foreground.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_white_background.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_white_background.xml new file mode 100644 index 0000000000..3ca7095395 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_white_background.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_signal_white_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_signal_white_foreground.xml new file mode 100644 index 0000000000..76a6861d0f --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_signal_white_foreground.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_waves_background.xml b/app/src/main/res/drawable/ic_launcher_alt_waves_background.xml new file mode 100644 index 0000000000..654f4fd98b --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_waves_background.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_waves_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_waves_foreground.xml new file mode 100644 index 0000000000..0916fc01ed --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_waves_foreground.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_waves_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_waves_monochrome.xml new file mode 100644 index 0000000000..e04d1da443 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_waves_monochrome.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_weather_background.xml b/app/src/main/res/drawable/ic_launcher_alt_weather_background.xml new file mode 100644 index 0000000000..e286725d7d --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_weather_background.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_weather_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_weather_foreground.xml new file mode 100644 index 0000000000..3e107964ad --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_weather_foreground.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_weather_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_weather_monochrome.xml new file mode 100644 index 0000000000..b3e1991d54 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_weather_monochrome.xml @@ -0,0 +1,28 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_yellow_background.xml b/app/src/main/res/drawable/ic_launcher_alt_yellow_background.xml new file mode 100644 index 0000000000..996ada4c34 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_yellow_background.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_yellow_foreground.xml b/app/src/main/res/drawable/ic_launcher_alt_yellow_foreground.xml new file mode 100644 index 0000000000..09a47f54a1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_yellow_foreground.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_alt_yellow_monochrome.xml b/app/src/main/res/drawable/ic_launcher_alt_yellow_monochrome.xml new file mode 100644 index 0000000000..ebf5ec2ebb --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_alt_yellow_monochrome.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml index c521e002c2..77f3eec8fa 100644 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -8,7 +8,7 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_app_icon_settings.xml b/app/src/main/res/layout/activity_app_icon_settings.xml new file mode 100644 index 0000000000..f7b8965584 --- /dev/null +++ b/app/src/main/res/layout/activity_app_icon_settings.xml @@ -0,0 +1,11 @@ + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_bubbles.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_bubbles.xml new file mode 100644 index 0000000000..78eae4fa8e --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_bubbles.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_chat.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_chat.xml new file mode 100644 index 0000000000..e7d0a4ab86 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_chat.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_news.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_news.xml new file mode 100644 index 0000000000..d2798924c3 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_news.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_notes.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_notes.xml new file mode 100644 index 0000000000..a9b905988f --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_notes.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_color.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_color.xml new file mode 100644 index 0000000000..df0e8dd73d --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark.xml new file mode 100644 index 0000000000..3752ec25e3 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark_variant.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark_variant.xml new file mode 100644 index 0000000000..d217d0f080 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_dark_variant.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_white.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_white.xml new file mode 100644 index 0000000000..d4aff19ff4 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_signal_white.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_waves.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_waves.xml new file mode 100644 index 0000000000..e3f14bcad5 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_waves.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_weather.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_weather.xml new file mode 100644 index 0000000000..b5ca6467fb --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_weather.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_yellow.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_yellow.xml new file mode 100644 index 0000000000..b2cdd306fa --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_alt_yellow.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/app_settings.xml b/app/src/main/res/navigation/app_settings.xml index 5948721801..fed1e0d2bf 100644 --- a/app/src/main/res/navigation/app_settings.xml +++ b/app/src/main/res/navigation/app_settings.xml @@ -237,6 +237,14 @@ app:exitAnim="@anim/fragment_open_exit" app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5fa589b92b..f9442e111d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -24,6 +24,15 @@ Save Note to Self + + Weather + + Notes + + News + + Waves + \+%d @@ -2884,6 +2893,28 @@ Appearance Theme Chat color & wallpaper + + App Icon + + OK + + Cancel + + Change app icon and name to \"%1$s\" + + Signal will need to close to change the app icon and name. Notifications will always display the default Signal icon and name. + + Select an app icon and name, which will be visible on your phone\'s home screen and app drawer. Notifications will always display the default Signal icon and name. Learn\u00A0more + + App icons and names are visible on the home screen and app drawer. + + Notifications will always display the default Signal icon and name. + + Learn\u00A0more + + Icon for %1$s + + Graphic illustrating where the replacement app icon will be visible. Disable PIN Enable PIN If you disable the PIN, you will lose all data when you re-register Signal unless you manually back up and restore. You can not turn on Registration Lock while the PIN is disabled.