Compare commits
3 Commits
982dfc5dff
...
43bcfdff1b
| Author | SHA1 | Date | |
|---|---|---|---|
| 43bcfdff1b | |||
| 810913b28e | |||
| 9d0cab3f53 |
@@ -23,8 +23,8 @@ val gitShortSha = safeGitOutput("rev-parse", "--short", "HEAD") ?: "unknown"
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// Rosetta versioning — bump here on each release
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
val rosettaVersionName = "1.1.5"
|
||||
val rosettaVersionCode = 17 // Increment on each release
|
||||
val rosettaVersionName = "1.1.6"
|
||||
val rosettaVersionCode = 18 // Increment on each release
|
||||
|
||||
android {
|
||||
namespace = "com.rosetta.messenger"
|
||||
|
||||
@@ -72,6 +72,8 @@ class MainActivity : FragmentActivity() {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MainActivity"
|
||||
// Process-memory session cache: lets app return without password while process is alive.
|
||||
private var cachedDecryptedAccount: DecryptedAccount? = null
|
||||
|
||||
// 🔔 FCM Логи для отображения в UI
|
||||
private val _fcmLogs = mutableStateListOf<String>()
|
||||
@@ -87,8 +89,18 @@ class MainActivity : FragmentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
fun clearFcmLogs() {
|
||||
_fcmLogs.clear()
|
||||
fun clearFcmLogs() {
|
||||
_fcmLogs.clear()
|
||||
}
|
||||
|
||||
private fun cacheSessionAccount(account: DecryptedAccount?) {
|
||||
cachedDecryptedAccount = account
|
||||
}
|
||||
|
||||
private fun getCachedSessionAccount(): DecryptedAccount? = cachedDecryptedAccount
|
||||
|
||||
private fun clearCachedSessionAccount() {
|
||||
cachedDecryptedAccount = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,14 +164,12 @@ class MainActivity : FragmentActivity() {
|
||||
var showSplash by remember { mutableStateOf(true) }
|
||||
var showOnboarding by remember { mutableStateOf(true) }
|
||||
var hasExistingAccount by remember { mutableStateOf<Boolean?>(null) }
|
||||
var currentAccount by remember { mutableStateOf<DecryptedAccount?>(null) }
|
||||
var currentAccount by remember { mutableStateOf(getCachedSessionAccount()) }
|
||||
var accountInfoList by remember { mutableStateOf<List<AccountInfo>>(emptyList()) }
|
||||
var startCreateAccountFlow by remember { mutableStateOf(false) }
|
||||
|
||||
// Check for existing accounts and build AccountInfo list
|
||||
// Also force logout so user always sees unlock screen on app restart
|
||||
LaunchedEffect(Unit) {
|
||||
accountManager.logout() // Always start logged out
|
||||
val accounts = accountManager.getAllAccounts()
|
||||
hasExistingAccount = accounts.isNotEmpty()
|
||||
accountInfoList = accounts.map { it.toAccountInfo() }
|
||||
@@ -239,6 +249,7 @@ class MainActivity : FragmentActivity() {
|
||||
onAuthComplete = { account ->
|
||||
startCreateAccountFlow = false
|
||||
currentAccount = account
|
||||
cacheSessionAccount(account)
|
||||
hasExistingAccount = true
|
||||
// Save as last logged account
|
||||
account?.let {
|
||||
@@ -256,6 +267,7 @@ class MainActivity : FragmentActivity() {
|
||||
// Set currentAccount to null immediately to prevent UI
|
||||
// lag
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
scope.launch {
|
||||
com.rosetta.messenger.network.ProtocolManager
|
||||
.disconnect()
|
||||
@@ -283,6 +295,7 @@ class MainActivity : FragmentActivity() {
|
||||
// Set currentAccount to null immediately to prevent UI
|
||||
// lag
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
scope.launch {
|
||||
com.rosetta.messenger.network.ProtocolManager
|
||||
.disconnect()
|
||||
@@ -315,6 +328,7 @@ class MainActivity : FragmentActivity() {
|
||||
hasExistingAccount = accounts.isNotEmpty()
|
||||
// 8. Navigate away last
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("DeleteAccount", "Failed to delete account", e)
|
||||
}
|
||||
@@ -353,6 +367,7 @@ class MainActivity : FragmentActivity() {
|
||||
// 9. If current account is deleted, return to main login screen
|
||||
if (currentAccount?.publicKey == targetPublicKey) {
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("DeleteAccount", "Failed to delete account from sidebar", e)
|
||||
@@ -367,6 +382,7 @@ class MainActivity : FragmentActivity() {
|
||||
|
||||
// Switch to another account: logout current, then show unlock.
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
scope.launch {
|
||||
com.rosetta.messenger.network.ProtocolManager.disconnect()
|
||||
accountManager.logout()
|
||||
@@ -375,6 +391,7 @@ class MainActivity : FragmentActivity() {
|
||||
onAddAccount = {
|
||||
startCreateAccountFlow = true
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
scope.launch {
|
||||
com.rosetta.messenger.network.ProtocolManager.disconnect()
|
||||
accountManager.logout()
|
||||
@@ -387,6 +404,7 @@ class MainActivity : FragmentActivity() {
|
||||
isDarkTheme = isDarkTheme,
|
||||
onExit = {
|
||||
currentAccount = null
|
||||
clearCachedSessionAccount()
|
||||
scope.launch {
|
||||
ProtocolManager.disconnect()
|
||||
accountManager.logout()
|
||||
|
||||
@@ -17,17 +17,18 @@ object ReleaseNotes {
|
||||
val RELEASE_NOTICE = """
|
||||
Update v$VERSION_PLACEHOLDER
|
||||
|
||||
Подключение
|
||||
- Ускорен старт соединения и handshake при входе в аккаунт
|
||||
- Логика reconnect синхронизирована с desktop-поведением
|
||||
- Обновлён серверный endpoint на основной production (wss)
|
||||
Профили и аватарки
|
||||
- Добавлен полноэкранный просмотр аватарок в чужом профиле (включая системные аккаунты)
|
||||
- Исправлено отображение даты аватарки: устранён некорректный год (например, 58154)
|
||||
|
||||
Группы
|
||||
- Добавлено предзагруженное кэширование участников группы
|
||||
- Убран скачок "0 members" при повторном открытии группы
|
||||
Сессии и вход
|
||||
- Добавлен кэш сессии в памяти процесса: повторный пароль не запрашивается, пока процесс жив
|
||||
- Кэш сессии корректно очищается при выходе, переключении и удалении аккаунта
|
||||
|
||||
Интерфейс
|
||||
- Исправлено вертикальное выравнивание verified-галочки в списке чатов
|
||||
- Исправлено центрирование blur-фона у системных аватарок
|
||||
- Унифицировано определение темы для verified-галочек
|
||||
- В списке чатов verified-галочки сделаны синими в светлой теме (включая system light)
|
||||
""".trimIndent()
|
||||
|
||||
fun getNotice(version: String): String =
|
||||
|
||||
@@ -935,7 +935,7 @@ fun ChatsListScreen(
|
||||
VerifiedBadge(
|
||||
verified = if (accountVerified > 0) accountVerified else 1,
|
||||
size = 15,
|
||||
badgeTint = Color(0xFFACD2F9)
|
||||
badgeTint = PrimaryBlue
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3891,7 +3891,9 @@ fun DialogItemContent(
|
||||
VerifiedBadge(
|
||||
verified = if (dialog.verified > 0) dialog.verified else 1,
|
||||
size = 16,
|
||||
modifier = Modifier.offset(y = (-2).dp)
|
||||
modifier = Modifier.offset(y = (-2).dp),
|
||||
isDarkTheme = isDarkTheme,
|
||||
badgeTint = PrimaryBlue
|
||||
)
|
||||
}
|
||||
// 🔒 Красная иконка замочка для заблокированных пользователей
|
||||
|
||||
@@ -335,7 +335,7 @@ fun GroupInfoScreen(
|
||||
val secondaryText = Color(0xFF8E8E93)
|
||||
val accentColor = if (isDarkTheme) Color(0xFF5AA5FF) else Color(0xFF228BE6)
|
||||
val actionContentColor = if (isDarkTheme) Color.White else Color(0xFF1C1C1E)
|
||||
val groupActionButtonBlue = if (isDarkTheme) Color(0xFF285683) else Color(0xFF2478C2)
|
||||
val groupActionButtonBlue = if (isDarkTheme) Color(0xFF4A4A4D) else Color(0xFF2478C2)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
@@ -2,6 +2,11 @@ package com.rosetta.messenger.ui.components
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapShader
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.graphics.Shader
|
||||
import android.os.Build
|
||||
import android.renderscript.Allocation
|
||||
import android.renderscript.Element
|
||||
@@ -32,6 +37,7 @@ import com.rosetta.messenger.repository.AvatarRepository
|
||||
import com.rosetta.messenger.utils.AvatarFileManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* Компонент для отображения размытого фона аватарки
|
||||
@@ -63,7 +69,11 @@ fun BoxScope.BlurredAvatarBackground(
|
||||
LaunchedEffect(avatarKey, publicKey) {
|
||||
val currentAvatars = avatars
|
||||
val newOriginal = withContext(Dispatchers.IO) {
|
||||
if (currentAvatars.isNotEmpty()) {
|
||||
// Keep system account blur source identical to the visible avatar drawable.
|
||||
// This prevents offset/parallax mismatches when server avatar payload differs.
|
||||
if (MessageRepository.isSystemAccount(publicKey)) {
|
||||
loadSystemAvatarBitmap(context, publicKey)
|
||||
} else if (currentAvatars.isNotEmpty()) {
|
||||
AvatarFileManager.base64ToBitmap(currentAvatars.first().base64Data)
|
||||
} else {
|
||||
loadSystemAvatarBitmap(context, publicKey)
|
||||
@@ -183,7 +193,78 @@ private fun loadSystemAvatarBitmap(context: Context, publicKey: String): Bitmap?
|
||||
val drawable = AppCompatResources.getDrawable(context, resId) ?: return null
|
||||
val width = drawable.intrinsicWidth.takeIf { it > 0 } ?: 256
|
||||
val height = drawable.intrinsicHeight.takeIf { it > 0 } ?: 256
|
||||
return drawable.toBitmap(width = width, height = height, config = Bitmap.Config.ARGB_8888)
|
||||
val source = drawable.toBitmap(width = width, height = height, config = Bitmap.Config.ARGB_8888)
|
||||
return recenterSystemBlurSource(source)
|
||||
}
|
||||
|
||||
private data class FocusCenter(val x: Float, val y: Float)
|
||||
|
||||
private fun recenterSystemBlurSource(source: Bitmap): Bitmap {
|
||||
val focusCenter = detectSystemFocusCenter(source) ?: return source
|
||||
val dx = source.width / 2f - focusCenter.x
|
||||
val dy = source.height / 2f - focusCenter.y
|
||||
|
||||
if (abs(dx) < 0.5f && abs(dy) < 0.5f) return source
|
||||
|
||||
val output = Bitmap.createBitmap(source.width, source.height, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(output)
|
||||
val shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
|
||||
val matrix = Matrix().apply { setTranslate(dx, dy) }
|
||||
shader.setLocalMatrix(matrix)
|
||||
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
this.shader = shader
|
||||
isFilterBitmap = true
|
||||
isDither = true
|
||||
}
|
||||
canvas.drawRect(0f, 0f, source.width.toFloat(), source.height.toFloat(), paint)
|
||||
return output
|
||||
}
|
||||
|
||||
private fun detectSystemFocusCenter(source: Bitmap): FocusCenter? {
|
||||
val width = source.width
|
||||
val height = source.height
|
||||
if (width < 2 || height < 2) return null
|
||||
|
||||
val cornerColors = intArrayOf(
|
||||
source.getPixel(0, 0),
|
||||
source.getPixel(width - 1, 0),
|
||||
source.getPixel(0, height - 1),
|
||||
source.getPixel(width - 1, height - 1)
|
||||
)
|
||||
val bgR = cornerColors.map { android.graphics.Color.red(it) }.average().toFloat()
|
||||
val bgG = cornerColors.map { android.graphics.Color.green(it) }.average().toFloat()
|
||||
val bgB = cornerColors.map { android.graphics.Color.blue(it) }.average().toFloat()
|
||||
|
||||
val step = (minOf(width, height) / 140).coerceAtLeast(1)
|
||||
val threshold = 54f
|
||||
var weightedX = 0f
|
||||
var weightedY = 0f
|
||||
var totalWeight = 0f
|
||||
|
||||
var y = 0
|
||||
while (y < height) {
|
||||
var x = 0
|
||||
while (x < width) {
|
||||
val pixel = source.getPixel(x, y)
|
||||
val dr = abs(android.graphics.Color.red(pixel) - bgR)
|
||||
val dg = abs(android.graphics.Color.green(pixel) - bgG)
|
||||
val db = abs(android.graphics.Color.blue(pixel) - bgB)
|
||||
val weight = (dr + dg + db) - threshold
|
||||
if (weight > 0f) {
|
||||
weightedX += x * weight
|
||||
weightedY += y * weight
|
||||
totalWeight += weight
|
||||
}
|
||||
x += step
|
||||
}
|
||||
y += step
|
||||
}
|
||||
|
||||
if (totalWeight <= 0f) return null
|
||||
return FocusCenter(
|
||||
x = weightedX / totalWeight,
|
||||
y = weightedY / totalWeight
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.rosetta.messenger.ui.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.*
|
||||
@@ -16,6 +15,7 @@ import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import com.rosetta.messenger.R
|
||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||
import com.rosetta.messenger.ui.theme.LocalRosettaIsDarkTheme
|
||||
|
||||
/**
|
||||
* Значок верификации пользователя
|
||||
@@ -23,14 +23,14 @@ import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||
*
|
||||
* @param verified Уровень верификации (0 = нет, 1 = стандартная, 2+ = особая)
|
||||
* @param size Размер значка в dp
|
||||
* @param isDarkTheme Тема приложения (если не передано - используется системная)
|
||||
* @param isDarkTheme Тема приложения (если не передано - вычисляется из MaterialTheme)
|
||||
*/
|
||||
@Composable
|
||||
fun VerifiedBadge(
|
||||
verified: Int,
|
||||
size: Int = 16,
|
||||
modifier: Modifier = Modifier,
|
||||
isDarkTheme: Boolean = isSystemInDarkTheme(),
|
||||
isDarkTheme: Boolean = LocalRosettaIsDarkTheme.current,
|
||||
badgeTint: Color? = null
|
||||
) {
|
||||
if (verified <= 0) return
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
@@ -51,6 +52,7 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
@@ -192,6 +194,9 @@ fun OtherProfileScreen(
|
||||
var isBlocked by remember { mutableStateOf(false) }
|
||||
var showAvatarMenu by remember { mutableStateOf(false) }
|
||||
var showImageViewer by remember { mutableStateOf(false) }
|
||||
var showAvatarViewer by remember { mutableStateOf(false) }
|
||||
var avatarViewerBitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
|
||||
var avatarViewerTimestamp by remember { mutableStateOf(0L) }
|
||||
var imageViewerInitialIndex by remember { mutableIntStateOf(0) }
|
||||
var selectedTab by remember { mutableStateOf(OtherProfileTab.MEDIA) }
|
||||
val pagerState = rememberPagerState(
|
||||
@@ -212,12 +217,12 @@ fun OtherProfileScreen(
|
||||
snapshotFlow { pagerState.currentPage }.collect { page ->
|
||||
selectedTab = OtherProfileTab.entries[page]
|
||||
// Swipe-back only on first tab (Media); on other tabs pager handles swipe
|
||||
onSwipeBackEnabledChanged(page == 0 && !showImageViewer)
|
||||
onSwipeBackEnabledChanged(page == 0 && !showImageViewer && !showAvatarViewer)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(showImageViewer) {
|
||||
onSwipeBackEnabledChanged(!showImageViewer && pagerState.currentPage == 0)
|
||||
LaunchedEffect(showImageViewer, showAvatarViewer) {
|
||||
onSwipeBackEnabledChanged(!showImageViewer && !showAvatarViewer && pagerState.currentPage == 0)
|
||||
}
|
||||
|
||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||
@@ -1123,6 +1128,43 @@ fun OtherProfileScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
onAvatarLongPress = {
|
||||
coroutineScope.launch {
|
||||
when {
|
||||
hasAvatar && avatars.isNotEmpty() -> {
|
||||
val first = avatars.first()
|
||||
avatarViewerTimestamp = first.timestamp
|
||||
val bitmap = withContext(Dispatchers.IO) {
|
||||
AvatarFileManager.base64ToBitmap(first.base64Data)
|
||||
}
|
||||
if (bitmap != null) {
|
||||
avatarViewerBitmap = bitmap
|
||||
showAvatarViewer = true
|
||||
}
|
||||
}
|
||||
user.publicKey == MessageRepository.SYSTEM_SAFE_PUBLIC_KEY -> {
|
||||
val bitmap = withContext(Dispatchers.IO) {
|
||||
BitmapFactory.decodeResource(context.resources, R.drawable.safe_account)
|
||||
}
|
||||
if (bitmap != null) {
|
||||
avatarViewerTimestamp = 0L
|
||||
avatarViewerBitmap = bitmap
|
||||
showAvatarViewer = true
|
||||
}
|
||||
}
|
||||
user.publicKey == MessageRepository.SYSTEM_UPDATES_PUBLIC_KEY -> {
|
||||
val bitmap = withContext(Dispatchers.IO) {
|
||||
BitmapFactory.decodeResource(context.resources, R.drawable.updates_account)
|
||||
}
|
||||
if (bitmap != null) {
|
||||
avatarViewerTimestamp = 0L
|
||||
avatarViewerBitmap = bitmap
|
||||
showAvatarViewer = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
backgroundBlurColorId = backgroundBlurColorId
|
||||
)
|
||||
|
||||
@@ -1135,6 +1177,16 @@ fun OtherProfileScreen(
|
||||
isDarkTheme = isDarkTheme
|
||||
)
|
||||
}
|
||||
|
||||
FullScreenAvatarViewer(
|
||||
isVisible = showAvatarViewer,
|
||||
onDismiss = { showAvatarViewer = false },
|
||||
displayName = user.title.ifBlank { user.publicKey.take(10) },
|
||||
avatarTimestamp = avatarViewerTimestamp,
|
||||
avatarBitmap = avatarViewerBitmap,
|
||||
publicKey = user.publicKey,
|
||||
isDarkTheme = isDarkTheme
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1815,6 +1867,7 @@ private fun CollapsingOtherProfileHeader(
|
||||
onBlockToggle: () -> Unit,
|
||||
avatarRepository: AvatarRepository? = null,
|
||||
onClearChat: () -> Unit,
|
||||
onAvatarLongPress: () -> Unit = {},
|
||||
backgroundBlurColorId: String = "avatar"
|
||||
) {
|
||||
val density = LocalDensity.current
|
||||
@@ -1943,7 +1996,12 @@ private fun CollapsingOtherProfileHeader(
|
||||
shape = RoundedCornerShape(cornerRadius)
|
||||
clip = true
|
||||
}
|
||||
.background(avatarColors.backgroundColor),
|
||||
.background(avatarColors.backgroundColor)
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onLongPress = { onAvatarLongPress() }
|
||||
)
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
if (publicKey == MessageRepository.SYSTEM_SAFE_PUBLIC_KEY) {
|
||||
|
||||
@@ -2074,7 +2074,13 @@ fun FullScreenAvatarViewer(
|
||||
val dateText = remember(avatarTimestamp) {
|
||||
if (avatarTimestamp > 0) {
|
||||
val sdf = SimpleDateFormat("MMMM d, yyyy 'at' h:mm a", Locale.ENGLISH)
|
||||
sdf.format(Date(avatarTimestamp * 1000))
|
||||
val normalizedTimestampMs = when {
|
||||
avatarTimestamp >= 1_000_000_000_000_000_000L -> avatarTimestamp / 1_000_000
|
||||
avatarTimestamp >= 1_000_000_000_000_000L -> avatarTimestamp / 1_000
|
||||
avatarTimestamp >= 1_000_000_000_000L -> avatarTimestamp
|
||||
else -> avatarTimestamp * 1_000
|
||||
}
|
||||
sdf.format(Date(normalizedTimestampMs))
|
||||
} else ""
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import androidx.core.view.WindowCompat
|
||||
import com.rosetta.messenger.ui.utils.NavigationModeUtils
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
val LocalRosettaIsDarkTheme = staticCompositionLocalOf { true }
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = DarkPrimary,
|
||||
secondary = Accent,
|
||||
@@ -78,9 +80,11 @@ fun RosettaAndroidTheme(
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
CompositionLocalProvider(LocalRosettaIsDarkTheme provides darkTheme) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user