Смена иконки приложения — калькулятор, погода, заметки + экран выбора в настройка
This commit is contained in:
@@ -47,10 +47,7 @@
|
|||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode|smallestScreenSize|screenLayout"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode|smallestScreenSize|screenLayout"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:screenOrientation="portrait">
|
android:screenOrientation="portrait">
|
||||||
<intent-filter>
|
<!-- LAUNCHER intent-filter moved to activity-alias entries for icon switching -->
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
@@ -65,6 +62,63 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<!-- App Icon Aliases: only one enabled at a time -->
|
||||||
|
<activity-alias
|
||||||
|
android:name=".MainActivityDefault"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:label="@string/app_name">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".MainActivityCalculator"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:enabled="false"
|
||||||
|
android:exported="true"
|
||||||
|
android:icon="@mipmap/ic_launcher_calc"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_calc"
|
||||||
|
android:label="Calculator">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".MainActivityWeather"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:enabled="false"
|
||||||
|
android:exported="true"
|
||||||
|
android:icon="@mipmap/ic_launcher_weather"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_weather"
|
||||||
|
android:label="Weather">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
|
<activity-alias
|
||||||
|
android:name=".MainActivityNotes"
|
||||||
|
android:targetActivity=".MainActivity"
|
||||||
|
android:enabled="false"
|
||||||
|
android:exported="true"
|
||||||
|
android:icon="@mipmap/ic_launcher_notes"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_notes"
|
||||||
|
android:label="Notes">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".IncomingCallActivity"
|
android:name=".IncomingCallActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -672,6 +672,7 @@ sealed class Screen {
|
|||||||
data object CrashLogs : Screen()
|
data object CrashLogs : Screen()
|
||||||
data object Biometric : Screen()
|
data object Biometric : Screen()
|
||||||
data object Appearance : Screen()
|
data object Appearance : Screen()
|
||||||
|
data object AppIcon : Screen()
|
||||||
data object QrScanner : Screen()
|
data object QrScanner : Screen()
|
||||||
data object MyQr : Screen()
|
data object MyQr : Screen()
|
||||||
}
|
}
|
||||||
@@ -1031,6 +1032,9 @@ fun MainScreen(
|
|||||||
val isAppearanceVisible by remember {
|
val isAppearanceVisible by remember {
|
||||||
derivedStateOf { navStack.any { it is Screen.Appearance } }
|
derivedStateOf { navStack.any { it is Screen.Appearance } }
|
||||||
}
|
}
|
||||||
|
val isAppIconVisible by remember {
|
||||||
|
derivedStateOf { navStack.any { it is Screen.AppIcon } }
|
||||||
|
}
|
||||||
val isQrScannerVisible by remember { derivedStateOf { navStack.any { it is Screen.QrScanner } } }
|
val isQrScannerVisible by remember { derivedStateOf { navStack.any { it is Screen.QrScanner } } }
|
||||||
val isMyQrVisible by remember { derivedStateOf { navStack.any { it is Screen.MyQr } } }
|
val isMyQrVisible by remember { derivedStateOf { navStack.any { it is Screen.MyQr } } }
|
||||||
var profileHasUnsavedChanges by remember(accountPublicKey) { mutableStateOf(false) }
|
var profileHasUnsavedChanges by remember(accountPublicKey) { mutableStateOf(false) }
|
||||||
@@ -1437,12 +1441,25 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onToggleTheme = onToggleTheme,
|
onToggleTheme = onToggleTheme,
|
||||||
|
onAppIconClick = { navStack = navStack + Screen.AppIcon },
|
||||||
accountPublicKey = accountPublicKey,
|
accountPublicKey = accountPublicKey,
|
||||||
accountName = accountName,
|
accountName = accountName,
|
||||||
avatarRepository = avatarRepository
|
avatarRepository = avatarRepository
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwipeBackContainer(
|
||||||
|
isVisible = isAppIconVisible,
|
||||||
|
onBack = { navStack = navStack.filterNot { it is Screen.AppIcon } },
|
||||||
|
isDarkTheme = isDarkTheme,
|
||||||
|
layer = 3
|
||||||
|
) {
|
||||||
|
com.rosetta.messenger.ui.settings.AppIconScreen(
|
||||||
|
isDarkTheme = isDarkTheme,
|
||||||
|
onBack = { navStack = navStack.filterNot { it is Screen.AppIcon } }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
SwipeBackContainer(
|
SwipeBackContainer(
|
||||||
isVisible = isUpdatesVisible,
|
isVisible = isUpdatesVisible,
|
||||||
onBack = { navStack = navStack.filterNot { it is Screen.Updates } },
|
onBack = { navStack = navStack.filterNot { it is Screen.Updates } },
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ class PreferencesManager(private val context: Context) {
|
|||||||
val BACKGROUND_BLUR_COLOR_ID =
|
val BACKGROUND_BLUR_COLOR_ID =
|
||||||
stringPreferencesKey("background_blur_color_id") // id from BackgroundBlurPresets
|
stringPreferencesKey("background_blur_color_id") // id from BackgroundBlurPresets
|
||||||
|
|
||||||
|
// App Icon disguise: "default", "calculator", "weather", "notes"
|
||||||
|
val APP_ICON = stringPreferencesKey("app_icon")
|
||||||
|
|
||||||
// Pinned Chats (max 3)
|
// Pinned Chats (max 3)
|
||||||
val PINNED_CHATS = stringSetPreferencesKey("pinned_chats") // Set of opponent public keys
|
val PINNED_CHATS = stringSetPreferencesKey("pinned_chats") // Set of opponent public keys
|
||||||
|
|
||||||
@@ -333,6 +336,19 @@ class PreferencesManager(private val context: Context) {
|
|||||||
return wasPinned
|
return wasPinned
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ═════════════════════════════════════════════════════════════
|
||||||
|
// 🎨 APP ICON
|
||||||
|
// ═════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
val appIcon: Flow<String> =
|
||||||
|
context.dataStore.data.map { preferences ->
|
||||||
|
preferences[APP_ICON] ?: "default"
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setAppIcon(value: String) {
|
||||||
|
context.dataStore.edit { preferences -> preferences[APP_ICON] = value }
|
||||||
|
}
|
||||||
|
|
||||||
// ═════════════════════════════════════════════════════════════
|
// ═════════════════════════════════════════════════════════════
|
||||||
// 🔕 MUTED CHATS
|
// 🔕 MUTED CHATS
|
||||||
// ═════════════════════════════════════════════════════════════
|
// ═════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@@ -0,0 +1,270 @@
|
|||||||
|
package com.rosetta.messenger.ui.settings
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import compose.icons.TablerIcons
|
||||||
|
import compose.icons.tablericons.ChevronLeft
|
||||||
|
import com.rosetta.messenger.R
|
||||||
|
import com.rosetta.messenger.data.PreferencesManager
|
||||||
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
data class AppIconOption(
|
||||||
|
val id: String,
|
||||||
|
val label: String,
|
||||||
|
val subtitle: String,
|
||||||
|
val aliasName: String,
|
||||||
|
val iconRes: Int,
|
||||||
|
val previewBg: Color
|
||||||
|
)
|
||||||
|
|
||||||
|
private val iconOptions = listOf(
|
||||||
|
AppIconOption("default", "Rosetta", "Original icon", ".MainActivityDefault", R.drawable.ic_launcher_foreground, Color(0xFF1B1B1B)),
|
||||||
|
AppIconOption("calculator", "Calculator", "Disguise as calculator", ".MainActivityCalculator", R.drawable.ic_calc_foreground, Color(0xFF795548)),
|
||||||
|
AppIconOption("weather", "Weather", "Disguise as weather app", ".MainActivityWeather", R.drawable.ic_weather_foreground, Color(0xFF42A5F5)),
|
||||||
|
AppIconOption("notes", "Notes", "Disguise as notes app", ".MainActivityNotes", R.drawable.ic_notes_foreground, Color(0xFFFFC107))
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun AppIconScreen(
|
||||||
|
isDarkTheme: Boolean,
|
||||||
|
onBack: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val prefs = remember { PreferencesManager(context) }
|
||||||
|
var currentIcon by remember { mutableStateOf("default") }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
currentIcon = prefs.appIcon.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||||
|
val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
|
||||||
|
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||||
|
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
|
||||||
|
val dividerColor = if (isDarkTheme) Color(0xFF38383A) else Color(0xFFE5E5EA)
|
||||||
|
|
||||||
|
// Status bar
|
||||||
|
val view = androidx.compose.ui.platform.LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
DisposableEffect(isDarkTheme) {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
val prev = insetsController.isAppearanceLightStatusBars
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
onDispose { insetsController.isAppearanceLightStatusBars = prev }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BackHandler { onBack() }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(backgroundColor)
|
||||||
|
) {
|
||||||
|
// ═══════════════════════════════════════════════════════
|
||||||
|
// TOP BAR — same style as SafetyScreen
|
||||||
|
// ═══════════════════════════════════════════════════════
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
color = backgroundColor
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = WindowInsets.statusBars.asPaddingValues().calculateTopPadding())
|
||||||
|
.padding(horizontal = 4.dp, vertical = 8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
IconButton(onClick = onBack) {
|
||||||
|
Icon(
|
||||||
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
|
contentDescription = "Back",
|
||||||
|
tint = textColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "App Icon",
|
||||||
|
fontSize = 20.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
color = textColor,
|
||||||
|
modifier = Modifier.padding(start = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════
|
||||||
|
// CONTENT
|
||||||
|
// ═══════════════════════════════════════════════════════
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
// Section header
|
||||||
|
Text(
|
||||||
|
text = "CHOOSE ICON",
|
||||||
|
fontSize = 13.sp,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = secondaryTextColor,
|
||||||
|
letterSpacing = 0.5.sp,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Icon cards in grouped surface (Telegram style)
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
color = surfaceColor
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
iconOptions.forEachIndexed { index, option ->
|
||||||
|
val isSelected = currentIcon == option.id
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable {
|
||||||
|
if (!isSelected) {
|
||||||
|
scope.launch {
|
||||||
|
changeAppIcon(context, prefs, option.id)
|
||||||
|
currentIcon = option.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
// Icon preview
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(52.dp)
|
||||||
|
.clip(RoundedCornerShape(12.dp))
|
||||||
|
.background(option.previewBg),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
// Default icon has 15% inset built-in — show full size
|
||||||
|
val iconSize = if (option.id == "default") 52.dp else 36.dp
|
||||||
|
val scaleType = if (option.id == "default")
|
||||||
|
android.widget.ImageView.ScaleType.CENTER_CROP
|
||||||
|
else
|
||||||
|
android.widget.ImageView.ScaleType.FIT_CENTER
|
||||||
|
androidx.compose.ui.viewinterop.AndroidView(
|
||||||
|
factory = { ctx ->
|
||||||
|
android.widget.ImageView(ctx).apply {
|
||||||
|
setImageResource(option.iconRes)
|
||||||
|
this.scaleType = scaleType
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.size(iconSize)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(14.dp))
|
||||||
|
|
||||||
|
// Label + subtitle
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = option.label,
|
||||||
|
color = textColor,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.Normal
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = option.subtitle,
|
||||||
|
color = secondaryTextColor,
|
||||||
|
fontSize = 13.sp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checkmark
|
||||||
|
if (isSelected) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Check,
|
||||||
|
contentDescription = "Selected",
|
||||||
|
tint = PrimaryBlue,
|
||||||
|
modifier = Modifier.size(22.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divider between items (not after last)
|
||||||
|
if (index < iconOptions.lastIndex) {
|
||||||
|
Divider(
|
||||||
|
modifier = Modifier.padding(start = 82.dp),
|
||||||
|
thickness = 0.5.dp,
|
||||||
|
color = dividerColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info text below
|
||||||
|
Text(
|
||||||
|
text = "The app icon and name on your home screen will change. Rosetta will continue to work normally. The launcher may take a moment to update.",
|
||||||
|
fontSize = 13.sp,
|
||||||
|
color = secondaryTextColor,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||||
|
lineHeight = 18.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun changeAppIcon(context: Context, prefs: PreferencesManager, newIconId: String) {
|
||||||
|
val pm = context.packageManager
|
||||||
|
val packageName = context.packageName
|
||||||
|
|
||||||
|
iconOptions.forEach { option ->
|
||||||
|
val component = ComponentName(packageName, "$packageName${option.aliasName}")
|
||||||
|
pm.setComponentEnabledSetting(
|
||||||
|
component,
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||||
|
PackageManager.DONT_KILL_APP
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val selected = iconOptions.first { it.id == newIconId }
|
||||||
|
val component = ComponentName(packageName, "$packageName${selected.aliasName}")
|
||||||
|
pm.setComponentEnabledSetting(
|
||||||
|
component,
|
||||||
|
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||||
|
PackageManager.DONT_KILL_APP
|
||||||
|
)
|
||||||
|
|
||||||
|
prefs.setAppIcon(newIconId)
|
||||||
|
Toast.makeText(context, "Icon changed to ${selected.label}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
@@ -78,6 +78,7 @@ fun AppearanceScreen(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onBlurColorChange: (String) -> Unit,
|
onBlurColorChange: (String) -> Unit,
|
||||||
onToggleTheme: () -> Unit = {},
|
onToggleTheme: () -> Unit = {},
|
||||||
|
onAppIconClick: () -> Unit = {},
|
||||||
accountPublicKey: String = "",
|
accountPublicKey: String = "",
|
||||||
accountName: String = "",
|
accountName: String = "",
|
||||||
avatarRepository: AvatarRepository? = null
|
avatarRepository: AvatarRepository? = null
|
||||||
@@ -282,6 +283,49 @@ fun AppearanceScreen(
|
|||||||
lineHeight = 18.sp
|
lineHeight = 18.sp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════
|
||||||
|
// APP ICON SECTION
|
||||||
|
// ═══════════════════════════════════════════════════════
|
||||||
|
Text(
|
||||||
|
text = "APP ICON",
|
||||||
|
fontSize = 13.sp,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = secondaryTextColor,
|
||||||
|
letterSpacing = 0.5.sp,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable { onAppIconClick() }
|
||||||
|
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Change App Icon",
|
||||||
|
fontSize = 16.sp,
|
||||||
|
color = textColor
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
imageVector = TablerIcons.ChevronRight,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = secondaryTextColor,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Disguise Rosetta as a calculator, weather app, or notes.",
|
||||||
|
fontSize = 13.sp,
|
||||||
|
color = secondaryTextColor,
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
lineHeight = 18.sp
|
||||||
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
app/src/main/res/drawable/ic_calc_background.xml
Normal file
4
app/src/main/res/drawable/ic_calc_background.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#795548"/>
|
||||||
|
</shape>
|
||||||
38
app/src/main/res/drawable/ic_calc_foreground.xml
Normal file
38
app/src/main/res/drawable/ic_calc_foreground.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<!-- Calculator — Google Calculator style: simple, bold, white on color -->
|
||||||
|
<group android:translateX="30" android:translateY="24">
|
||||||
|
<!-- = sign (equals, large, centered, bold) -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M6,22h36v5H6z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M6,33h36v5H6z" />
|
||||||
|
<!-- + sign (plus, smaller, top right) -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:alpha="0.7"
|
||||||
|
android:pathData="M34,2h4v16h-4z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:alpha="0.7"
|
||||||
|
android:pathData="M28,8h16v4H28z" />
|
||||||
|
<!-- ÷ sign (divide, bottom) -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:alpha="0.7"
|
||||||
|
android:pathData="M6,50h36v4H6z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:alpha="0.7"
|
||||||
|
android:pathData="M22,43a3,3,0,1,1,-3,3a3,3,0,0,1,3,-3z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:alpha="0.7"
|
||||||
|
android:pathData="M22,57a3,3,0,1,1,-3,3a3,3,0,0,1,3,-3z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
4
app/src/main/res/drawable/ic_notes_background.xml
Normal file
4
app/src/main/res/drawable/ic_notes_background.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#FFC107"/>
|
||||||
|
</shape>
|
||||||
52
app/src/main/res/drawable/ic_notes_foreground.xml
Normal file
52
app/src/main/res/drawable/ic_notes_foreground.xml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<!-- Notes — Google Keep style: white card with colored pin/accent -->
|
||||||
|
<group android:translateX="26" android:translateY="20">
|
||||||
|
<!-- Card shadow -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000020"
|
||||||
|
android:pathData="M5,5h46c2.8,0 5,2.2 5,5v54c0,2.8 -2.2,5 -5,5H5c-2.8,0 -5,-2.2 -5,-5V10C0,7.2 2.2,5 5,5z" />
|
||||||
|
<!-- White card -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M5,2h46c2.8,0 5,2.2 5,5v54c0,2.8 -2.2,5 -5,5H5c-2.8,0 -5,-2.2 -5,-5V7C0,4.2 2.2,2 5,2z" />
|
||||||
|
<!-- Checkbox checked -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFA000"
|
||||||
|
android:pathData="M6,14h6v6H6z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M7.5,17.5l1.5,1.5l3.5,-3.5"
|
||||||
|
android:strokeColor="#FFFFFF"
|
||||||
|
android:strokeWidth="1.5"/>
|
||||||
|
<!-- Text line 1 (next to checkbox) -->
|
||||||
|
<path android:fillColor="#757575" android:pathData="M16,15h32v3H16z" />
|
||||||
|
<!-- Checkbox unchecked -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#BDBDBD"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:pathData="M6,28h6v6H6z" />
|
||||||
|
<!-- Text line 2 -->
|
||||||
|
<path android:fillColor="#BDBDBD" android:pathData="M16,29h28v3H16z" />
|
||||||
|
<!-- Checkbox unchecked -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#BDBDBD"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:pathData="M6,42h6v6H6z" />
|
||||||
|
<!-- Text line 3 -->
|
||||||
|
<path android:fillColor="#BDBDBD" android:pathData="M16,43h22v3H16z" />
|
||||||
|
<!-- Checkbox unchecked -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#BDBDBD"
|
||||||
|
android:strokeWidth="1.5"
|
||||||
|
android:pathData="M6,56h6v6H6z" />
|
||||||
|
<!-- Text line 4 -->
|
||||||
|
<path android:fillColor="#BDBDBD" android:pathData="M16,57h18v3H16z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
4
app/src/main/res/drawable/ic_weather_background.xml
Normal file
4
app/src/main/res/drawable/ic_weather_background.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="#42A5F5"/>
|
||||||
|
</shape>
|
||||||
32
app/src/main/res/drawable/ic_weather_foreground.xml
Normal file
32
app/src/main/res/drawable/ic_weather_foreground.xml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<!-- Weather — sun with cloud, Material You style, centered in safe zone -->
|
||||||
|
<group android:translateX="20" android:translateY="20">
|
||||||
|
<!-- Sun glow (soft circle) -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFF9C4"
|
||||||
|
android:pathData="M34,24a14,14,0,1,1,-14,14a14,14,0,0,1,14,-14z" />
|
||||||
|
<!-- Sun core -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFB300"
|
||||||
|
android:pathData="M34,28a10,10,0,1,1,-10,10a10,10,0,0,1,10,-10z" />
|
||||||
|
<!-- Sun rays -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFB300"
|
||||||
|
android:pathData="M33,12h2v8h-2zM33,48h2v8h-2zM12,37v-2h8v2zM48,37v-2h8v2z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFB300"
|
||||||
|
android:pathData="M18.3,18.3l1.4,1.4l5.7,5.7l-1.4,1.4l-5.7,-5.7zM42.6,42.6l1.4,1.4l5.7,5.7l-1.4,1.4l-5.7,-5.7zM18.3,49.7l5.7,-5.7l1.4,1.4l-5.7,5.7zM42.6,25.4l5.7,-5.7l1.4,1.4l-5.7,5.7z" />
|
||||||
|
<!-- Cloud (in front of sun) -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M52,44c4.4,0 8,3.6 8,8s-3.6,8 -8,8H20c-5.5,0 -10,-4.5 -10,-10s4.5,-10 10,-10c0.5,0 1,0 1.5,0.1C23.2,35.2 28,32 34,32c6.4,0 11.7,4.4 13.2,10.3C49,42.1 50.5,42 52,44z" />
|
||||||
|
<!-- Cloud shadow hint -->
|
||||||
|
<path
|
||||||
|
android:fillColor="#E0E0E0"
|
||||||
|
android:pathData="M20,58h32c2.5,0 4.8,-0.8 6.6,-2H14C16,57 17.9,58 20,58z" />
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_calc.xml
Normal file
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_calc.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_calc_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_calc_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_notes.xml
Normal file
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_notes.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_notes_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_notes_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_weather_background"/>
|
||||||
|
<foreground android:drawable="@drawable/ic_weather_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
Reference in New Issue
Block a user