Add new drawable resources for messaging features across multiple resolutions
- Added various icons including msg_palette, msg_photos, msg_pin, msg_retry, msg_secret, msg_send, msg_sendfile, msg_theme, msg_unpin, msg_views, and msg_warning in drawable-hdpi, drawable-mdpi, drawable-xhdpi, and drawable-xxhdpi directories. - Included fingerprint, ic_ab_done, ic_ab_other, ic_ab_reply, ic_arrow_drop_down, input_attach, input_keyboard, input_smile, and menu_unlock icons in respective drawable directories. - Enhanced user interface with new icons for better visual representation in messaging functionalities.
@@ -9,12 +9,14 @@ import androidx.compose.foundation.text.KeyboardOptions
|
|||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
@@ -75,7 +77,15 @@ fun SetPasswordScreen(
|
|||||||
var visible by remember { mutableStateOf(false) }
|
var visible by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
// Track keyboard visibility
|
// Track keyboard visibility
|
||||||
val view = androidx.compose.ui.platform.LocalView.current
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
var isKeyboardVisible by remember { mutableStateOf(false) }
|
var isKeyboardVisible by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
DisposableEffect(view) {
|
DisposableEffect(view) {
|
||||||
@@ -106,7 +116,7 @@ fun SetPasswordScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack, enabled = !isCreating) {
|
IconButton(onClick = onBack, enabled = !isCreating) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = textColor.copy(alpha = 0.6f)
|
tint = textColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
@@ -280,7 +290,7 @@ fun SetPasswordScreen(
|
|||||||
else -> Color(0xFF4CAF50)
|
else -> Color(0xFF4CAF50)
|
||||||
}
|
}
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Shield,
|
painter = TelegramIcons.Secret,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = strengthColor,
|
tint = strengthColor,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -306,7 +316,7 @@ fun SetPasswordScreen(
|
|||||||
verticalAlignment = Alignment.Top
|
verticalAlignment = Alignment.Top
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.AlertTriangle,
|
painter = TelegramIcons.Warning,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color(0xFFE53935),
|
tint = Color(0xFFE53935),
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -446,7 +456,7 @@ fun SetPasswordScreen(
|
|||||||
verticalAlignment = Alignment.Top
|
verticalAlignment = Alignment.Top
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.InfoCircle,
|
painter = TelegramIcons.Info,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -504,7 +505,7 @@ fun UnlockScreen(
|
|||||||
|
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
@@ -645,7 +646,7 @@ fun UnlockScreen(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.LockOpen,
|
painter = TelegramIcons.Unlock,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
)
|
)
|
||||||
@@ -663,7 +664,7 @@ fun UnlockScreen(
|
|||||||
enabled = !isUnlocking
|
enabled = !isUnlocking
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Fingerprint,
|
painter = TelegramIcons.Fingerprint,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
@@ -719,7 +720,7 @@ fun UnlockScreen(
|
|||||||
|
|
||||||
TextButton(onClick = onSwitchAccount) {
|
TextButton(onClick = onSwitchAccount) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.UserPlus,
|
painter = TelegramIcons.AddContact,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ import androidx.compose.foundation.shape.CircleShape
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import compose.icons.TablerIcons
|
||||||
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
@@ -117,6 +120,15 @@ fun ChatDetailScreen(
|
|||||||
val database = RosettaDatabase.getDatabase(context)
|
val database = RosettaDatabase.getDatabase(context)
|
||||||
val hapticFeedback = LocalHapticFeedback.current
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
|
||||||
|
// 🔇 Mute state — read from PreferencesManager
|
||||||
|
val preferencesManager = remember { com.rosetta.messenger.data.PreferencesManager(context) }
|
||||||
|
val isChatMuted = remember { mutableStateOf(false) }
|
||||||
|
LaunchedEffect(currentUserPublicKey, user.publicKey) {
|
||||||
|
if (currentUserPublicKey.isNotBlank()) {
|
||||||
|
isChatMuted.value = preferencesManager.isChatMuted(currentUserPublicKey, user.publicKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UI Theme
|
// UI Theme
|
||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFF2F2F7)
|
||||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||||
@@ -192,17 +204,24 @@ fun ChatDetailScreen(
|
|||||||
var imageViewerSourceBounds by remember { mutableStateOf<ImageSourceBounds?>(null) }
|
var imageViewerSourceBounds by remember { mutableStateOf<ImageSourceBounds?>(null) }
|
||||||
var imageViewerImages by remember { mutableStateOf<List<ViewableImage>>(emptyList()) }
|
var imageViewerImages by remember { mutableStateOf<List<ViewableImage>>(emptyList()) }
|
||||||
|
|
||||||
// 🎨 Управление статус баром
|
// 🎨 Управление статус баром — ВСЕГДА чёрные иконки в светлой теме
|
||||||
DisposableEffect(isDarkTheme, showImageViewer, window, view) {
|
if (!view.isInEditMode) {
|
||||||
if (showImageViewer) {
|
SideEffect {
|
||||||
// 📸 При просмотре фото - чёрные system bars
|
if (showImageViewer) {
|
||||||
SystemBarsStyleUtils.applyFullscreenDark(window, view)
|
SystemBarsStyleUtils.applyFullscreenDark(window, view)
|
||||||
} else {
|
} else {
|
||||||
// Обычный режим чата
|
if (window != null && view != null) {
|
||||||
SystemBarsStyleUtils.applyChatStatusBar(window, view, isDarkTheme)
|
val ic = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
ic.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposableEffect(Unit) {
|
||||||
onDispose {
|
onDispose {
|
||||||
|
// Восстановить при уходе с экрана
|
||||||
SystemBarsStyleUtils.applyChatStatusBar(window, view, isDarkTheme)
|
SystemBarsStyleUtils.applyChatStatusBar(window, view, isDarkTheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,16 +581,10 @@ fun ChatDetailScreen(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default
|
painter = TelegramIcons.Close,
|
||||||
.Close,
|
|
||||||
contentDescription =
|
contentDescription =
|
||||||
"Cancel",
|
"Cancel",
|
||||||
tint =
|
tint = headerIconColor,
|
||||||
if (isDarkTheme
|
|
||||||
)
|
|
||||||
Color.White
|
|
||||||
else
|
|
||||||
Color.Black,
|
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.size(
|
Modifier.size(
|
||||||
24.dp
|
24.dp
|
||||||
@@ -657,12 +670,7 @@ fun ChatDetailScreen(
|
|||||||
.ContentCopy,
|
.ContentCopy,
|
||||||
contentDescription =
|
contentDescription =
|
||||||
"Copy",
|
"Copy",
|
||||||
tint =
|
tint = headerIconColor,
|
||||||
if (isDarkTheme
|
|
||||||
)
|
|
||||||
Color.White
|
|
||||||
else
|
|
||||||
Color.Black,
|
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.size(
|
Modifier.size(
|
||||||
22.dp
|
22.dp
|
||||||
@@ -697,12 +705,7 @@ fun ChatDetailScreen(
|
|||||||
.Delete,
|
.Delete,
|
||||||
contentDescription =
|
contentDescription =
|
||||||
"Delete",
|
"Delete",
|
||||||
tint =
|
tint = headerIconColor,
|
||||||
if (isDarkTheme
|
|
||||||
)
|
|
||||||
Color.White
|
|
||||||
else
|
|
||||||
Color.Black,
|
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.size(
|
Modifier.size(
|
||||||
22.dp
|
22.dp
|
||||||
@@ -735,8 +738,7 @@ fun ChatDetailScreen(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
.KeyboardArrowLeft,
|
|
||||||
contentDescription =
|
contentDescription =
|
||||||
"Back",
|
"Back",
|
||||||
tint =
|
tint =
|
||||||
@@ -749,7 +751,7 @@ fun ChatDetailScreen(
|
|||||||
),
|
),
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.size(
|
Modifier.size(
|
||||||
32.dp
|
28.dp
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -987,6 +989,16 @@ fun ChatDetailScreen(
|
|||||||
isDarkTheme
|
isDarkTheme
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// 🔇 Mute icon
|
||||||
|
if (isChatMuted.value) {
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Icon(
|
||||||
|
painter = TelegramIcons.Mute,
|
||||||
|
contentDescription = "Muted",
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
tint = secondaryTextColor
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Typing indicator или
|
// Typing indicator или
|
||||||
// subtitle
|
// subtitle
|
||||||
@@ -1886,6 +1898,16 @@ fun ChatDetailScreen(
|
|||||||
avatarRepository,
|
avatarRepository,
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
// 📳 Haptic feedback при долгом нажатии
|
// 📳 Haptic feedback при долгом нажатии
|
||||||
|
// Не разрешаем выделять avatar-сообщения
|
||||||
|
val hasAvatar =
|
||||||
|
message.attachments
|
||||||
|
.any {
|
||||||
|
it.type ==
|
||||||
|
AttachmentType
|
||||||
|
.AVATAR
|
||||||
|
}
|
||||||
|
if (hasAvatar) return@MessageBubble
|
||||||
|
|
||||||
hapticFeedback
|
hapticFeedback
|
||||||
.performHapticFeedback(
|
.performHapticFeedback(
|
||||||
HapticFeedbackType
|
HapticFeedbackType
|
||||||
@@ -1922,7 +1944,14 @@ fun ChatDetailScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
if (isSelectionMode
|
val hasAvatar =
|
||||||
|
message.attachments
|
||||||
|
.any {
|
||||||
|
it.type ==
|
||||||
|
AttachmentType
|
||||||
|
.AVATAR
|
||||||
|
}
|
||||||
|
if (isSelectionMode && !hasAvatar
|
||||||
) {
|
) {
|
||||||
selectedMessages =
|
selectedMessages =
|
||||||
if (selectedMessages
|
if (selectedMessages
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import androidx.compose.foundation.gestures.awaitFirstDown
|
|||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
@@ -23,6 +24,7 @@ import androidx.compose.ui.draw.clipToBounds
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.graphics.lerp
|
import androidx.compose.ui.graphics.lerp
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
|
import androidx.compose.ui.input.pointer.changedToUpIgnoreConsumed
|
||||||
import androidx.compose.ui.input.pointer.pointerInput
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
import androidx.compose.ui.input.pointer.positionChange
|
import androidx.compose.ui.input.pointer.positionChange
|
||||||
@@ -57,6 +59,7 @@ import androidx.compose.ui.graphics.painter.Painter
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -220,21 +223,22 @@ fun ChatsListScreen(
|
|||||||
focusManager.clearFocus()
|
focusManager.clearFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update status bar appearance — SideEffect overrides global Theme.kt SideEffect
|
// Update status bar appearance — only set once on entry, not every recomposition
|
||||||
if (!view.isInEditMode) {
|
// This prevents overriding ChatDetailScreen's status bar when ChatsListScreen is in back stack
|
||||||
SideEffect {
|
DisposableEffect(isDarkTheme) {
|
||||||
val window = (view.context as android.app.Activity).window
|
val window = (view.context as android.app.Activity).window
|
||||||
val insetsController =
|
val insetsController =
|
||||||
androidx.core.view.WindowCompat.getInsetsController(window, view)
|
androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
|
||||||
// Status bar — always white icons (header is blue)
|
// Status bar — always white icons (header is blue)
|
||||||
insetsController.isAppearanceLightStatusBars = false
|
insetsController.isAppearanceLightStatusBars = false
|
||||||
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
|
||||||
// Navigation bar: показываем только если есть нативные кнопки
|
// Navigation bar
|
||||||
com.rosetta.messenger.ui.utils.NavigationModeUtils
|
com.rosetta.messenger.ui.utils.NavigationModeUtils
|
||||||
.applyNavigationBarVisibility(insetsController, context, isDarkTheme)
|
.applyNavigationBarVisibility(insetsController, context, isDarkTheme)
|
||||||
}
|
|
||||||
|
onDispose { }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Colors - instant change, no animation - 🔥 КЭШИРУЕМ для производительности
|
// Colors - instant change, no animation - 🔥 КЭШИРУЕМ для производительности
|
||||||
@@ -490,21 +494,35 @@ fun ChatsListScreen(
|
|||||||
)
|
)
|
||||||
val headerColor = avatarColors.backgroundColor
|
val headerColor = avatarColors.backgroundColor
|
||||||
|
|
||||||
// Header с размытым фоном аватарки
|
// Header с blur аватарки (fallback = голубой) или акцентным цветом (light)
|
||||||
Box(modifier = Modifier.fillMaxWidth()) {
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
BlurredAvatarBackground(
|
if (isDarkTheme) {
|
||||||
publicKey = accountPublicKey,
|
if (backgroundBlurColorId == "solid_blue") {
|
||||||
avatarRepository = avatarRepository,
|
// Голубой фон
|
||||||
fallbackColor = headerColor,
|
Box(
|
||||||
blurRadius = 40f,
|
modifier = Modifier
|
||||||
alpha = 0.6f,
|
.matchParentSize()
|
||||||
overlayColors =
|
.background(PrimaryBlueDark)
|
||||||
BackgroundBlurPresets
|
)
|
||||||
.getOverlayColors(
|
} else {
|
||||||
backgroundBlurColorId
|
// Avatar blur (default)
|
||||||
),
|
BlurredAvatarBackground(
|
||||||
isDarkTheme = isDarkTheme
|
publicKey = accountPublicKey,
|
||||||
)
|
avatarRepository = avatarRepository,
|
||||||
|
fallbackColor = PrimaryBlueDark,
|
||||||
|
blurRadius = 40f,
|
||||||
|
alpha = 0.6f,
|
||||||
|
overlayColors = emptyList(),
|
||||||
|
isDarkTheme = isDarkTheme
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.matchParentSize()
|
||||||
|
.background(PrimaryBlue)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Content поверх фона
|
// Content поверх фона
|
||||||
Column(
|
Column(
|
||||||
@@ -689,7 +707,7 @@ fun ChatsListScreen(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(8.dp)
|
modifier = Modifier.size(8.dp)
|
||||||
@@ -734,7 +752,7 @@ fun ChatsListScreen(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Plus,
|
painter = TelegramIcons.Add,
|
||||||
contentDescription = "Add Account",
|
contentDescription = "Add Account",
|
||||||
tint = if (isDarkTheme) Color(0xFF828282) else Color(0xFF889198),
|
tint = if (isDarkTheme) Color(0xFF828282) else Color(0xFF889198),
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
@@ -866,7 +884,7 @@ fun ChatsListScreen(
|
|||||||
|
|
||||||
// Logout
|
// Logout
|
||||||
DrawerMenuItemEnhanced(
|
DrawerMenuItemEnhanced(
|
||||||
icon = TablerIcons.Logout,
|
painter = TelegramIcons.Leave,
|
||||||
text = "Log Out",
|
text = "Log Out",
|
||||||
iconColor = Color(0xFFFF4444),
|
iconColor = Color(0xFFFF4444),
|
||||||
textColor = Color(0xFFFF4444),
|
textColor = Color(0xFFFF4444),
|
||||||
@@ -923,7 +941,7 @@ fun ChatsListScreen(
|
|||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = { selectedChatKeys = emptySet() }) {
|
IconButton(onClick = { selectedChatKeys = emptySet() }) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Close",
|
contentDescription = "Close",
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
@@ -950,7 +968,7 @@ fun ChatsListScreen(
|
|||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
if (allMuted) TablerIcons.Bell else TablerIcons.BellOff,
|
painter = if (allMuted) TelegramIcons.Notifications else TelegramIcons.Mute,
|
||||||
contentDescription = if (allMuted) "Unmute" else "Mute",
|
contentDescription = if (allMuted) "Unmute" else "Mute",
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
@@ -964,7 +982,7 @@ fun ChatsListScreen(
|
|||||||
selectedChatKeys = emptySet()
|
selectedChatKeys = emptySet()
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Trash,
|
painter = TelegramIcons.Delete,
|
||||||
contentDescription = "Delete",
|
contentDescription = "Delete",
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
@@ -974,7 +992,7 @@ fun ChatsListScreen(
|
|||||||
Box {
|
Box {
|
||||||
IconButton(onClick = { showSelectionMenu = true }) {
|
IconButton(onClick = { showSelectionMenu = true }) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.DotsVertical,
|
painter = TelegramIcons.More,
|
||||||
contentDescription = "More",
|
contentDescription = "More",
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
@@ -1000,7 +1018,7 @@ fun ChatsListScreen(
|
|||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
if (allPinned) TablerIcons.PinnedOff else TablerIcons.Pin,
|
painter = if (allPinned) TelegramIcons.Unpin else TelegramIcons.Pin,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (isDarkTheme) Color.White else Color.Black
|
tint = if (isDarkTheme) Color.White else Color.Black
|
||||||
)
|
)
|
||||||
@@ -1028,7 +1046,7 @@ fun ChatsListScreen(
|
|||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Ban,
|
painter = TelegramIcons.Block,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color(0xFFE53935)
|
tint = Color(0xFFE53935)
|
||||||
)
|
)
|
||||||
@@ -1089,10 +1107,10 @@ fun ChatsListScreen(
|
|||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.TopEnd)
|
.align(Alignment.TopEnd)
|
||||||
.offset(x = 2.dp, y = (-2).dp)
|
.offset(x = 4.dp, y = (-4).dp)
|
||||||
.size(8.dp)
|
.size(10.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(if (isDarkTheme) PrimaryBlueDark else PrimaryBlue)
|
.background(if (isDarkTheme) Color.White else PrimaryBlue)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1208,7 +1226,7 @@ fun ChatsListScreen(
|
|||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Edit,
|
painter = TelegramIcons.Edit,
|
||||||
contentDescription = "New Chat"
|
contentDescription = "New Chat"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1444,9 +1462,55 @@ fun ChatsListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track scroll direction to hide/show Requests
|
||||||
|
val chatListState = rememberLazyListState()
|
||||||
|
var isRequestsVisible by remember { mutableStateOf(true) }
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
|
||||||
|
// NestedScroll — ловим направление свайпа даже без скролла
|
||||||
|
// Для появления: накапливаем pull down дельту, нужен сильный жест
|
||||||
|
val requestsNestedScroll = remember(hapticFeedback) {
|
||||||
|
var accumulatedPullDown = 0f
|
||||||
|
object : androidx.compose.ui.input.nestedscroll.NestedScrollConnection {
|
||||||
|
override fun onPreScroll(
|
||||||
|
available: androidx.compose.ui.geometry.Offset,
|
||||||
|
source: androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||||
|
): androidx.compose.ui.geometry.Offset {
|
||||||
|
if (available.y < -10f) {
|
||||||
|
// Свайп вверх — прячем легко
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
isRequestsVisible = false
|
||||||
|
} else if (available.y > 0f && !isRequestsVisible) {
|
||||||
|
// Свайп вниз — накапливаем для появления
|
||||||
|
accumulatedPullDown += available.y
|
||||||
|
if (accumulatedPullDown > 120f) {
|
||||||
|
isRequestsVisible = true
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
hapticFeedback.performHapticFeedback(
|
||||||
|
HapticFeedbackType.LongPress
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else if (available.y <= 0f) {
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
}
|
||||||
|
return androidx.compose.ui.geometry.Offset.Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun onPostFling(
|
||||||
|
consumed: androidx.compose.ui.unit.Velocity,
|
||||||
|
available: androidx.compose.ui.unit.Velocity
|
||||||
|
): androidx.compose.ui.unit.Velocity {
|
||||||
|
accumulatedPullDown = 0f
|
||||||
|
return androidx.compose.ui.unit.Velocity.Zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
|
state = chatListState,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.fillMaxSize()
|
Modifier.fillMaxSize()
|
||||||
|
.nestedScroll(requestsNestedScroll)
|
||||||
.background(
|
.background(
|
||||||
listBackgroundColor
|
listBackgroundColor
|
||||||
)
|
)
|
||||||
@@ -1456,23 +1520,35 @@ fun ChatsListScreen(
|
|||||||
key =
|
key =
|
||||||
"requests_section"
|
"requests_section"
|
||||||
) {
|
) {
|
||||||
RequestsSection(
|
AnimatedVisibility(
|
||||||
count =
|
visible = isRequestsVisible,
|
||||||
requestsCount,
|
enter = expandVertically(
|
||||||
requests =
|
animationSpec = tween(250, easing = FastOutSlowInEasing)
|
||||||
requests,
|
) + fadeIn(animationSpec = tween(200)),
|
||||||
isDarkTheme =
|
exit = shrinkVertically(
|
||||||
isDarkTheme,
|
animationSpec = tween(250, easing = FastOutSlowInEasing)
|
||||||
onClick = {
|
) + fadeOut(animationSpec = tween(200))
|
||||||
onRequestsClick()
|
) {
|
||||||
|
Column {
|
||||||
|
RequestsSection(
|
||||||
|
count =
|
||||||
|
requestsCount,
|
||||||
|
requests =
|
||||||
|
requests,
|
||||||
|
isDarkTheme =
|
||||||
|
isDarkTheme,
|
||||||
|
onClick = {
|
||||||
|
onRequestsClick()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Divider(
|
||||||
|
color =
|
||||||
|
dividerColor,
|
||||||
|
thickness =
|
||||||
|
0.5.dp
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
Divider(
|
|
||||||
color =
|
|
||||||
dividerColor,
|
|
||||||
thickness =
|
|
||||||
0.5.dp
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1980,7 +2056,7 @@ fun ChatItem(
|
|||||||
if (isMuted) {
|
if (isMuted) {
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.BellOff,
|
painter = TelegramIcons.Mute,
|
||||||
contentDescription = "Muted",
|
contentDescription = "Muted",
|
||||||
tint = secondaryTextColor,
|
tint = secondaryTextColor,
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1990,7 +2066,7 @@ fun ChatItem(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
// Read status
|
// Read status
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Checks,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -2028,7 +2104,7 @@ fun ChatItem(
|
|||||||
// Pin icon
|
// Pin icon
|
||||||
if (chat.isPinned) {
|
if (chat.isPinned) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Pin,
|
painter = TelegramIcons.Pin,
|
||||||
contentDescription = "Pinned",
|
contentDescription = "Pinned",
|
||||||
tint =
|
tint =
|
||||||
secondaryTextColor.copy(
|
secondaryTextColor.copy(
|
||||||
@@ -2262,9 +2338,9 @@ fun SwipeableDialogItem(
|
|||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector =
|
painter =
|
||||||
if (isPinned) TablerIcons.PinnedOff
|
if (isPinned) TelegramIcons.Unpin
|
||||||
else TablerIcons.Pin,
|
else TelegramIcons.Pin,
|
||||||
contentDescription =
|
contentDescription =
|
||||||
if (isPinned) "Unpin" else "Pin",
|
if (isPinned) "Unpin" else "Pin",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
@@ -2303,9 +2379,9 @@ fun SwipeableDialogItem(
|
|||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector =
|
painter =
|
||||||
if (isBlocked) TablerIcons.LockOpen
|
if (isBlocked) TelegramIcons.Unlock
|
||||||
else TablerIcons.Ban,
|
else TelegramIcons.Block,
|
||||||
contentDescription =
|
contentDescription =
|
||||||
if (isBlocked) "Unblock"
|
if (isBlocked) "Unblock"
|
||||||
else "Block",
|
else "Block",
|
||||||
@@ -2343,7 +2419,7 @@ fun SwipeableDialogItem(
|
|||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Trash,
|
painter = TelegramIcons.Delete,
|
||||||
contentDescription = "Delete",
|
contentDescription = "Delete",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
@@ -2742,7 +2818,7 @@ fun DialogItemContent(
|
|||||||
if (isBlocked) {
|
if (isBlocked) {
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Lock,
|
painter = TelegramIcons.Secret,
|
||||||
contentDescription = "Blocked",
|
contentDescription = "Blocked",
|
||||||
tint = Color(0xFFFF3B30),
|
tint = Color(0xFFFF3B30),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -2751,7 +2827,7 @@ fun DialogItemContent(
|
|||||||
if (isMuted) {
|
if (isMuted) {
|
||||||
Spacer(modifier = Modifier.width(4.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.BellOff,
|
painter = TelegramIcons.Mute,
|
||||||
contentDescription = "Muted",
|
contentDescription = "Muted",
|
||||||
tint = secondaryTextColor,
|
tint = secondaryTextColor,
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -2767,7 +2843,7 @@ fun DialogItemContent(
|
|||||||
// галочки (прочитано)
|
// галочки (прочитано)
|
||||||
if (dialog.isSavedMessages) {
|
if (dialog.isSavedMessages) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Checks,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -2810,8 +2886,8 @@ fun DialogItemContent(
|
|||||||
// READ (delivered=3) - две синие
|
// READ (delivered=3) - две синие
|
||||||
// галочки
|
// галочки
|
||||||
Icon(
|
Icon(
|
||||||
imageVector =
|
painter =
|
||||||
TablerIcons.Checks,
|
TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier =
|
modifier =
|
||||||
@@ -2825,8 +2901,8 @@ fun DialogItemContent(
|
|||||||
1 -> {
|
1 -> {
|
||||||
// DELIVERED - одна серая галочка
|
// DELIVERED - одна серая галочка
|
||||||
Icon(
|
Icon(
|
||||||
imageVector =
|
painter =
|
||||||
TablerIcons.Check,
|
TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint =
|
tint =
|
||||||
secondaryTextColor
|
secondaryTextColor
|
||||||
@@ -2845,8 +2921,8 @@ fun DialogItemContent(
|
|||||||
else -> {
|
else -> {
|
||||||
// SENDING (0) - часики
|
// SENDING (0) - часики
|
||||||
Icon(
|
Icon(
|
||||||
imageVector =
|
painter =
|
||||||
TablerIcons.Clock,
|
TelegramIcons.Clock,
|
||||||
contentDescription =
|
contentDescription =
|
||||||
"Sending",
|
"Sending",
|
||||||
tint =
|
tint =
|
||||||
@@ -2988,7 +3064,7 @@ fun DialogItemContent(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Spacer(modifier = Modifier.width(6.dp))
|
Spacer(modifier = Modifier.width(6.dp))
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Pin,
|
painter = TelegramIcons.Pin,
|
||||||
contentDescription = "Pinned",
|
contentDescription = "Pinned",
|
||||||
tint = secondaryTextColor.copy(alpha = 0.5f),
|
tint = secondaryTextColor.copy(alpha = 0.5f),
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -3057,12 +3133,20 @@ fun RequestsSection(
|
|||||||
isDarkTheme: Boolean,
|
isDarkTheme: Boolean,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
val textColor = remember(isDarkTheme) { if (isDarkTheme) Color.White else Color.Black }
|
// Telegram archived chats uses muted colors:
|
||||||
val secondaryTextColor =
|
// Title: #525252 (light) vs regular #222222
|
||||||
remember(isDarkTheme) { if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666) }
|
// Message: #919191 (light)
|
||||||
|
// Badge: always grey #c6c9cc (light)
|
||||||
|
// Avatar bg: #B8C2CC (light) / #3A3A3C (dark)
|
||||||
|
val titleColor = remember(isDarkTheme) {
|
||||||
|
if (isDarkTheme) Color(0xFFAAAAAA) else Color(0xFF525252)
|
||||||
|
}
|
||||||
|
val subtitleColor =
|
||||||
|
remember(isDarkTheme) { if (isDarkTheme) Color(0xFF6E6E6E) else Color(0xFF919191) }
|
||||||
val iconBgColor =
|
val iconBgColor =
|
||||||
remember(isDarkTheme) { if (isDarkTheme) Color(0xFF3A3A3C) else Color(0xFFC7C7CC) }
|
remember(isDarkTheme) { if (isDarkTheme) Color(0xFF3A3A3C) else Color(0xFFB8C2CC) }
|
||||||
val accentColor = if (isDarkTheme) PrimaryBlueDark else PrimaryBlue
|
val badgeColor =
|
||||||
|
remember(isDarkTheme) { if (isDarkTheme) Color(0xFF4E4E4E) else Color(0xFFC6C9CC) }
|
||||||
|
|
||||||
// Последний запрос — показываем имя отправителя как subtitle
|
// Последний запрос — показываем имя отправителя как subtitle
|
||||||
val lastRequest = remember(requests) { requests.firstOrNull() }
|
val lastRequest = remember(requests) { requests.firstOrNull() }
|
||||||
@@ -3096,7 +3180,7 @@ fun RequestsSection(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.MailForward,
|
painter = painterResource(id = R.drawable.archive_filled),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(26.dp)
|
modifier = Modifier.size(26.dp)
|
||||||
@@ -3116,7 +3200,7 @@ fun RequestsSection(
|
|||||||
text = "Requests",
|
text = "Requests",
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
color = textColor,
|
color = titleColor,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
@@ -3130,7 +3214,7 @@ fun RequestsSection(
|
|||||||
Modifier
|
Modifier
|
||||||
.defaultMinSize(minWidth = 22.dp, minHeight = 22.dp)
|
.defaultMinSize(minWidth = 22.dp, minHeight = 22.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(accentColor),
|
.background(badgeColor),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -3151,20 +3235,13 @@ fun RequestsSection(
|
|||||||
Text(
|
Text(
|
||||||
text = subtitle,
|
text = subtitle,
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = secondaryTextColor,
|
color = subtitleColor,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Разделитель как у обычных чатов
|
|
||||||
Divider(
|
|
||||||
color = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE8E8E8),
|
|
||||||
thickness = 0.5.dp,
|
|
||||||
modifier = Modifier.padding(start = 84.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ private fun ForwardDialogItem(
|
|||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(
|
.background(
|
||||||
if (isSelected) Color(0xFF4CD964)
|
if (isSelected) PrimaryBlue
|
||||||
else if (isDarkTheme) Color(0xFF3A3A3A)
|
else if (isDarkTheme) Color(0xFF3A3A3A)
|
||||||
else Color(0xFFE0E0E0)
|
else Color(0xFFE0E0E0)
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ import androidx.compose.ui.unit.sp
|
|||||||
import com.rosetta.messenger.network.SearchUser
|
import com.rosetta.messenger.network.SearchUser
|
||||||
import com.rosetta.messenger.repository.AvatarRepository
|
import com.rosetta.messenger.repository.AvatarRepository
|
||||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.ChevronLeft
|
import compose.icons.tablericons.*
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.ArrowLeft
|
import compose.icons.tablericons.*
|
||||||
import compose.icons.tablericons.X
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Verified
|
import androidx.compose.material.icons.filled.Verified
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
@@ -61,6 +61,14 @@ fun SearchScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 🔥 Функция мгновенного закрытия клавиатуры
|
// 🔥 Функция мгновенного закрытия клавиатуры
|
||||||
val hideKeyboardInstantly: () -> Unit = {
|
val hideKeyboardInstantly: () -> Unit = {
|
||||||
@@ -173,7 +181,7 @@ fun SearchScreen(
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = textColor.copy(alpha = 0.6f)
|
tint = textColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
@@ -233,7 +241,7 @@ fun SearchScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = { searchViewModel.clearSearchQuery() }) {
|
IconButton(onClick = { searchViewModel.clearSearchQuery() }) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Clear",
|
contentDescription = "Clear",
|
||||||
tint = secondaryTextColor.copy(alpha = 0.6f)
|
tint = secondaryTextColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
@@ -424,7 +432,7 @@ private fun RecentUserItem(
|
|||||||
// Remove button
|
// Remove button
|
||||||
IconButton(onClick = onRemove, modifier = Modifier.size(40.dp)) {
|
IconButton(onClick = onRemove, modifier = Modifier.size(40.dp)) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Remove",
|
contentDescription = "Remove",
|
||||||
tint = secondaryTextColor.copy(alpha = 0.6f),
|
tint = secondaryTextColor.copy(alpha = 0.6f),
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
|||||||
import com.rosetta.messenger.utils.AttachmentFileManager
|
import com.rosetta.messenger.utils.AttachmentFileManager
|
||||||
import com.rosetta.messenger.utils.AvatarFileManager
|
import com.rosetta.messenger.utils.AvatarFileManager
|
||||||
import com.vanniktech.blurhash.BlurHash
|
import com.vanniktech.blurhash.BlurHash
|
||||||
import compose.icons.TablerIcons
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.tablericons.*
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
@@ -1174,7 +1173,7 @@ fun ImageAttachment(
|
|||||||
when (messageStatus) {
|
when (messageStatus) {
|
||||||
MessageStatus.SENDING -> {
|
MessageStatus.SENDING -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Clock,
|
painter = TelegramIcons.Clock,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1182,7 +1181,7 @@ fun ImageAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.SENT -> {
|
MessageStatus.SENT -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1190,7 +1189,7 @@ fun ImageAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.DELIVERED -> {
|
MessageStatus.DELIVERED -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1198,7 +1197,7 @@ fun ImageAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.READ -> {
|
MessageStatus.READ -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Checks,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1546,7 +1545,7 @@ fun FileAttachment(
|
|||||||
when (messageStatus) {
|
when (messageStatus) {
|
||||||
MessageStatus.SENDING -> {
|
MessageStatus.SENDING -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Clock,
|
painter = TelegramIcons.Clock,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1554,7 +1553,7 @@ fun FileAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.SENT -> {
|
MessageStatus.SENT -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1562,7 +1561,7 @@ fun FileAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.DELIVERED, MessageStatus.READ -> {
|
MessageStatus.DELIVERED, MessageStatus.READ -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Checks,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint =
|
tint =
|
||||||
if (messageStatus == MessageStatus.READ) {
|
if (messageStatus == MessageStatus.READ) {
|
||||||
@@ -1934,7 +1933,7 @@ fun AvatarAttachment(
|
|||||||
when (messageStatus) {
|
when (messageStatus) {
|
||||||
MessageStatus.SENDING -> {
|
MessageStatus.SENDING -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Clock,
|
painter = TelegramIcons.Clock,
|
||||||
contentDescription = "Sending",
|
contentDescription = "Sending",
|
||||||
tint = Color.White.copy(alpha = 0.6f),
|
tint = Color.White.copy(alpha = 0.6f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1942,7 +1941,7 @@ fun AvatarAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.SENT -> {
|
MessageStatus.SENT -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = "Sent",
|
contentDescription = "Sent",
|
||||||
tint = Color.White.copy(alpha = 0.6f),
|
tint = Color.White.copy(alpha = 0.6f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1950,7 +1949,7 @@ fun AvatarAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.DELIVERED -> {
|
MessageStatus.DELIVERED -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = "Delivered",
|
contentDescription = "Delivered",
|
||||||
tint = Color.White.copy(alpha = 0.6f),
|
tint = Color.White.copy(alpha = 0.6f),
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
@@ -1958,7 +1957,7 @@ fun AvatarAttachment(
|
|||||||
}
|
}
|
||||||
MessageStatus.READ -> {
|
MessageStatus.READ -> {
|
||||||
Icon(
|
Icon(
|
||||||
compose.icons.TablerIcons.Checks,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = "Read",
|
contentDescription = "Read",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ import com.rosetta.messenger.utils.AttachmentFileManager
|
|||||||
import com.vanniktech.blurhash.BlurHash
|
import com.vanniktech.blurhash.BlurHash
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@@ -392,7 +394,7 @@ fun MessageBubble(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.CornerUpLeft,
|
painter = TelegramIcons.Reply,
|
||||||
contentDescription = "Reply",
|
contentDescription = "Reply",
|
||||||
tint =
|
tint =
|
||||||
if (swipeProgress >= 1f) Color.White
|
if (swipeProgress >= 1f) Color.White
|
||||||
@@ -449,11 +451,11 @@ fun MessageBubble(
|
|||||||
Modifier.padding(start = 12.dp, end = 4.dp)
|
Modifier.padding(start = 12.dp, end = 4.dp)
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(Color(0xFF4CD964)),
|
.background(PrimaryBlue),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = "Selected",
|
contentDescription = "Selected",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -1026,28 +1028,33 @@ fun AnimatedMessageStatus(
|
|||||||
) { currentStatus ->
|
) { currentStatus ->
|
||||||
val iconSize = with(LocalDensity.current) { 14.sp.toDp() }
|
val iconSize = with(LocalDensity.current) { 14.sp.toDp() }
|
||||||
|
|
||||||
Icon(
|
if (currentStatus == MessageStatus.ERROR) {
|
||||||
imageVector =
|
Icon(
|
||||||
when (currentStatus) {
|
imageVector = TablerIcons.AlertCircle,
|
||||||
MessageStatus.SENDING -> TablerIcons.Clock
|
contentDescription = null,
|
||||||
MessageStatus.SENT -> TablerIcons.Check
|
tint = animatedColor,
|
||||||
MessageStatus.DELIVERED -> TablerIcons.Check
|
modifier =
|
||||||
MessageStatus.READ -> TablerIcons.Checks
|
Modifier.size(iconSize)
|
||||||
MessageStatus.ERROR -> TablerIcons.AlertCircle
|
.scale(scale)
|
||||||
},
|
.clickable {
|
||||||
contentDescription = null,
|
showErrorMenu = true
|
||||||
tint = animatedColor,
|
}
|
||||||
modifier =
|
)
|
||||||
Modifier.size(iconSize)
|
} else {
|
||||||
.scale(scale)
|
Icon(
|
||||||
.then(
|
painter =
|
||||||
if (currentStatus == MessageStatus.ERROR) {
|
when (currentStatus) {
|
||||||
Modifier.clickable {
|
MessageStatus.SENDING -> TelegramIcons.Clock
|
||||||
showErrorMenu = true
|
MessageStatus.SENT -> TelegramIcons.Done
|
||||||
}
|
MessageStatus.DELIVERED -> TelegramIcons.Done
|
||||||
} else Modifier
|
MessageStatus.READ -> TelegramIcons.Done
|
||||||
)
|
else -> TelegramIcons.Clock
|
||||||
)
|
},
|
||||||
|
contentDescription = null,
|
||||||
|
tint = animatedColor,
|
||||||
|
modifier = Modifier.size(iconSize).scale(scale)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
@@ -1062,7 +1069,7 @@ fun AnimatedMessageStatus(
|
|||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Refresh,
|
painter = TelegramIcons.Retry,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
)
|
)
|
||||||
@@ -1076,7 +1083,7 @@ fun AnimatedMessageStatus(
|
|||||||
},
|
},
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Trash,
|
painter = TelegramIcons.Delete,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color(0xFFE53935),
|
tint = Color(0xFFE53935),
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
@@ -1370,7 +1377,7 @@ fun ReplyBubble(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Photo,
|
painter = TelegramIcons.Photos,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(28.dp)
|
modifier = Modifier.size(28.dp)
|
||||||
@@ -1631,7 +1638,7 @@ private fun ForwardedImagePreview(
|
|||||||
} else {
|
} else {
|
||||||
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Photo,
|
painter = TelegramIcons.Photos,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(28.dp)
|
modifier = Modifier.size(28.dp)
|
||||||
@@ -1721,85 +1728,86 @@ fun KebabMenu(
|
|||||||
onDeleteClick: () -> Unit,
|
onDeleteClick: () -> Unit,
|
||||||
onLogsClick: () -> Unit = {}
|
onLogsClick: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val dividerColor =
|
val menuBgColor = if (isDarkTheme) Color(0xFF272829) else Color.White
|
||||||
if (isDarkTheme) Color.White.copy(alpha = 0.1f) else Color.Black.copy(alpha = 0.08f)
|
val textColor = if (isDarkTheme) Color.White else Color(0xFF222222)
|
||||||
|
val iconColor = if (isDarkTheme) Color.White.copy(alpha = 0.47f) else Color(0xFF676B70)
|
||||||
|
val dividerColor = if (isDarkTheme) Color(0xFF1C1D1F) else Color(0xFFF5F5F5)
|
||||||
|
|
||||||
DropdownMenu(
|
MaterialTheme(
|
||||||
expanded = expanded,
|
colorScheme = MaterialTheme.colorScheme.copy(
|
||||||
onDismissRequest = onDismiss,
|
surface = menuBgColor,
|
||||||
modifier = Modifier.width(220.dp),
|
onSurface = textColor
|
||||||
properties =
|
)
|
||||||
PopupProperties(
|
|
||||||
focusable = true,
|
|
||||||
dismissOnBackPress = true,
|
|
||||||
dismissOnClickOutside = true
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
if (!isSavedMessages) {
|
DropdownMenu(
|
||||||
KebabMenuItem(
|
expanded = expanded,
|
||||||
icon = if (isBlocked) TablerIcons.CircleCheck else TablerIcons.Ban,
|
onDismissRequest = onDismiss,
|
||||||
text = if (isBlocked) "Unblock User" else "Block User",
|
modifier = Modifier
|
||||||
onClick = { if (isBlocked) onUnblockClick() else onBlockClick() },
|
.defaultMinSize(minWidth = 196.dp)
|
||||||
tintColor = PrimaryBlue,
|
.background(menuBgColor),
|
||||||
textColor = if (isDarkTheme) Color.White else Color.Black
|
properties =
|
||||||
)
|
PopupProperties(
|
||||||
|
focusable = true,
|
||||||
|
dismissOnBackPress = true,
|
||||||
|
dismissOnClickOutside = true
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (!isSavedMessages) {
|
||||||
|
KebabMenuItem(
|
||||||
|
icon = if (isBlocked) TelegramIcons.Done else TelegramIcons.Block,
|
||||||
|
text = if (isBlocked) "Unblock User" else "Block User",
|
||||||
|
onClick = { if (isBlocked) onUnblockClick() else onBlockClick() },
|
||||||
|
tintColor = iconColor,
|
||||||
|
textColor = textColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Box(
|
// Delete chat
|
||||||
modifier =
|
KebabMenuItem(
|
||||||
Modifier.fillMaxWidth()
|
icon = TelegramIcons.Delete,
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
text = "Delete Chat",
|
||||||
.height(0.5.dp)
|
onClick = onDeleteClick,
|
||||||
.background(dividerColor)
|
tintColor = Color(0xFFFF3B30),
|
||||||
|
textColor = Color(0xFFFF3B30)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete chat
|
|
||||||
KebabMenuItem(
|
|
||||||
icon = TablerIcons.Trash,
|
|
||||||
text = "Delete Chat",
|
|
||||||
onClick = onDeleteClick,
|
|
||||||
tintColor = Color(0xFFFF3B30),
|
|
||||||
textColor = Color(0xFFFF3B30)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun KebabMenuItem(
|
private fun KebabMenuItem(
|
||||||
icon: ImageVector,
|
icon: Painter,
|
||||||
text: String,
|
text: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
tintColor: Color,
|
tintColor: Color,
|
||||||
textColor: Color
|
textColor: Color
|
||||||
) {
|
) {
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
// Telegram-style: 48dp height, 18dp horizontal padding
|
||||||
|
Box(
|
||||||
DropdownMenuItem(
|
modifier = Modifier
|
||||||
text = {
|
.fillMaxWidth()
|
||||||
Row(
|
.defaultMinSize(minWidth = 196.dp, minHeight = 48.dp)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
.clickable(onClick = onClick)
|
||||||
modifier = Modifier.fillMaxWidth()
|
.padding(horizontal = 18.dp),
|
||||||
) {
|
contentAlignment = Alignment.CenterStart
|
||||||
Icon(
|
) {
|
||||||
imageVector = icon,
|
Row(
|
||||||
contentDescription = null,
|
verticalAlignment = Alignment.CenterVertically
|
||||||
tint = tintColor,
|
) {
|
||||||
modifier = Modifier.size(24.dp)
|
Icon(
|
||||||
)
|
painter = icon,
|
||||||
Spacer(modifier = Modifier.width(14.dp))
|
contentDescription = null,
|
||||||
Text(
|
tint = tintColor,
|
||||||
text = text,
|
modifier = Modifier.size(24.dp)
|
||||||
color = textColor,
|
)
|
||||||
fontSize = 16.sp,
|
Spacer(modifier = Modifier.width(19.dp))
|
||||||
fontWeight = FontWeight.Medium
|
Text(
|
||||||
)
|
text = text,
|
||||||
}
|
color = textColor,
|
||||||
},
|
fontSize = 16.sp
|
||||||
onClick = onClick,
|
)
|
||||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 4.dp),
|
}
|
||||||
interactionSource = interactionSource,
|
}
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 12.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 🖼️ Превью изображения для reply в input bar (как в Telegram) */
|
/** 🖼️ Превью изображения для reply в input bar (как в Telegram) */
|
||||||
@@ -1949,7 +1957,7 @@ fun ReplyImagePreview(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Photo,
|
painter = TelegramIcons.Photos,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
@@ -1958,7 +1966,7 @@ fun ReplyImagePreview(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** Profile photo menu for avatar */
|
/** Profile photo menu for avatar — Telegram style */
|
||||||
@Composable
|
@Composable
|
||||||
fun ProfilePhotoMenu(
|
fun ProfilePhotoMenu(
|
||||||
expanded: Boolean,
|
expanded: Boolean,
|
||||||
@@ -1968,45 +1976,48 @@ fun ProfilePhotoMenu(
|
|||||||
onDeletePhotoClick: (() -> Unit)? = null,
|
onDeletePhotoClick: (() -> Unit)? = null,
|
||||||
hasAvatar: Boolean = false
|
hasAvatar: Boolean = false
|
||||||
) {
|
) {
|
||||||
val dividerColor =
|
// Telegram popup colors
|
||||||
if (isDarkTheme) Color.White.copy(alpha = 0.1f) else Color.Black.copy(alpha = 0.08f)
|
val menuBgColor = if (isDarkTheme) Color(0xFF272829) else Color.White
|
||||||
|
val textColor = if (isDarkTheme) Color.White else Color(0xFF222222)
|
||||||
|
val iconColor = if (isDarkTheme) Color.White.copy(alpha = 0.47f) else Color(0xFF676B70)
|
||||||
|
val dividerColor = if (isDarkTheme) Color(0xFF1C1D1F) else Color(0xFFF5F5F5)
|
||||||
|
|
||||||
DropdownMenu(
|
MaterialTheme(
|
||||||
expanded = expanded,
|
colorScheme = MaterialTheme.colorScheme.copy(
|
||||||
onDismissRequest = onDismiss,
|
surface = menuBgColor,
|
||||||
modifier = Modifier.width(220.dp),
|
onSurface = textColor
|
||||||
properties =
|
|
||||||
PopupProperties(
|
|
||||||
focusable = true,
|
|
||||||
dismissOnBackPress = true,
|
|
||||||
dismissOnClickOutside = true
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
ProfilePhotoMenuItem(
|
|
||||||
icon = TablerIcons.CameraPlus,
|
|
||||||
text = "Set Profile Photo",
|
|
||||||
onClick = onSetPhotoClick,
|
|
||||||
tintColor = if (isDarkTheme) Color.White else Color.Black,
|
|
||||||
textColor = if (isDarkTheme) Color.White else Color.Black
|
|
||||||
)
|
)
|
||||||
|
) {
|
||||||
// Показываем Delete только если есть аватар
|
DropdownMenu(
|
||||||
if (hasAvatar && onDeletePhotoClick != null) {
|
expanded = expanded,
|
||||||
Box(
|
onDismissRequest = onDismiss,
|
||||||
modifier =
|
modifier = Modifier
|
||||||
Modifier.fillMaxWidth()
|
.defaultMinSize(minWidth = 196.dp)
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
.background(menuBgColor),
|
||||||
.height(0.5.dp)
|
properties =
|
||||||
.background(dividerColor)
|
PopupProperties(
|
||||||
)
|
focusable = true,
|
||||||
|
dismissOnBackPress = true,
|
||||||
|
dismissOnClickOutside = true
|
||||||
|
)
|
||||||
|
) {
|
||||||
ProfilePhotoMenuItem(
|
ProfilePhotoMenuItem(
|
||||||
icon = TablerIcons.Trash,
|
icon = TelegramIcons.AddPhoto,
|
||||||
text = "Delete Photo",
|
text = if (hasAvatar) "Set Profile Photo" else "Add Photo",
|
||||||
onClick = onDeletePhotoClick,
|
onClick = onSetPhotoClick,
|
||||||
tintColor = Color(0xFFFF3B30),
|
tintColor = iconColor,
|
||||||
textColor = Color(0xFFFF3B30)
|
textColor = textColor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (hasAvatar && onDeletePhotoClick != null) {
|
||||||
|
ProfilePhotoMenuItem(
|
||||||
|
icon = TelegramIcons.Delete,
|
||||||
|
text = "Delete Photo",
|
||||||
|
onClick = onDeletePhotoClick,
|
||||||
|
tintColor = Color(0xFFFF3B30),
|
||||||
|
textColor = Color(0xFFFF3B30)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2021,80 +2032,81 @@ fun OtherProfileMenu(
|
|||||||
onBlockClick: () -> Unit,
|
onBlockClick: () -> Unit,
|
||||||
onClearChatClick: () -> Unit
|
onClearChatClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
val dividerColor =
|
val menuBgColor = if (isDarkTheme) Color(0xFF272829) else Color.White
|
||||||
if (isDarkTheme) Color.White.copy(alpha = 0.1f) else Color.Black.copy(alpha = 0.08f)
|
val textColor = if (isDarkTheme) Color.White else Color(0xFF222222)
|
||||||
|
val iconColor = if (isDarkTheme) Color.White.copy(alpha = 0.47f) else Color(0xFF676B70)
|
||||||
|
val dividerColor = if (isDarkTheme) Color(0xFF1C1D1F) else Color(0xFFF5F5F5)
|
||||||
|
|
||||||
DropdownMenu(
|
MaterialTheme(
|
||||||
expanded = expanded,
|
colorScheme = MaterialTheme.colorScheme.copy(
|
||||||
onDismissRequest = onDismiss,
|
surface = menuBgColor,
|
||||||
modifier = Modifier.width(220.dp),
|
onSurface = textColor
|
||||||
properties =
|
)
|
||||||
PopupProperties(
|
|
||||||
focusable = true,
|
|
||||||
dismissOnBackPress = true,
|
|
||||||
dismissOnClickOutside = true
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
ProfilePhotoMenuItem(
|
DropdownMenu(
|
||||||
icon = if (isBlocked) TablerIcons.CircleCheck else TablerIcons.Ban,
|
expanded = expanded,
|
||||||
text = if (isBlocked) "Unblock User" else "Block User",
|
onDismissRequest = onDismiss,
|
||||||
onClick = onBlockClick,
|
modifier = Modifier
|
||||||
tintColor = PrimaryBlue,
|
.defaultMinSize(minWidth = 196.dp)
|
||||||
textColor = if (isDarkTheme) Color.White else Color.Black
|
.background(menuBgColor),
|
||||||
)
|
properties =
|
||||||
|
PopupProperties(
|
||||||
|
focusable = true,
|
||||||
|
dismissOnBackPress = true,
|
||||||
|
dismissOnClickOutside = true
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
ProfilePhotoMenuItem(
|
||||||
|
icon = if (isBlocked) TelegramIcons.Done else TelegramIcons.Block,
|
||||||
|
text = if (isBlocked) "Unblock User" else "Block User",
|
||||||
|
onClick = onBlockClick,
|
||||||
|
tintColor = iconColor,
|
||||||
|
textColor = textColor
|
||||||
|
)
|
||||||
|
|
||||||
Box(
|
ProfilePhotoMenuItem(
|
||||||
modifier =
|
icon = TelegramIcons.Delete,
|
||||||
Modifier.fillMaxWidth()
|
text = "Clear Chat History",
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
onClick = onClearChatClick,
|
||||||
.height(0.5.dp)
|
tintColor = Color(0xFFFF3B30),
|
||||||
.background(dividerColor)
|
textColor = Color(0xFFFF3B30)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
ProfilePhotoMenuItem(
|
|
||||||
icon = TablerIcons.Trash,
|
|
||||||
text = "Clear Chat History",
|
|
||||||
onClick = onClearChatClick,
|
|
||||||
tintColor = Color(0xFFFF3B30),
|
|
||||||
textColor = Color(0xFFFF3B30)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ProfilePhotoMenuItem(
|
private fun ProfilePhotoMenuItem(
|
||||||
icon: ImageVector,
|
icon: Painter,
|
||||||
text: String,
|
text: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
tintColor: Color,
|
tintColor: Color,
|
||||||
textColor: Color
|
textColor: Color
|
||||||
) {
|
) {
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
// Telegram: 48dp height, 18dp horizontal padding, 16sp text, icon→text gap 43dp
|
||||||
|
Box(
|
||||||
DropdownMenuItem(
|
modifier = Modifier
|
||||||
text = {
|
.fillMaxWidth()
|
||||||
Row(
|
.defaultMinSize(minWidth = 196.dp, minHeight = 48.dp)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
.clickable(onClick = onClick)
|
||||||
modifier = Modifier.fillMaxWidth()
|
.padding(horizontal = 18.dp),
|
||||||
) {
|
contentAlignment = Alignment.CenterStart
|
||||||
Icon(
|
) {
|
||||||
imageVector = icon,
|
Row(
|
||||||
contentDescription = null,
|
verticalAlignment = Alignment.CenterVertically
|
||||||
tint = tintColor,
|
) {
|
||||||
modifier = Modifier.size(24.dp)
|
Icon(
|
||||||
)
|
painter = icon,
|
||||||
Spacer(modifier = Modifier.width(14.dp))
|
contentDescription = null,
|
||||||
Text(
|
tint = tintColor,
|
||||||
text = text,
|
modifier = Modifier.size(24.dp)
|
||||||
color = textColor,
|
)
|
||||||
fontSize = 16.sp,
|
Spacer(modifier = Modifier.width(19.dp))
|
||||||
fontWeight = FontWeight.Medium
|
Text(
|
||||||
)
|
text = text,
|
||||||
}
|
color = textColor,
|
||||||
},
|
fontSize = 16.sp
|
||||||
onClick = onClick,
|
)
|
||||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 4.dp),
|
}
|
||||||
interactionSource = interactionSource,
|
}
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 12.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.Bug
|
import compose.icons.tablericons.Bug
|
||||||
import compose.icons.tablericons.Trash
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,7 +165,7 @@ fun DebugLogsBottomSheet(
|
|||||||
Row {
|
Row {
|
||||||
IconButton(onClick = onClearLogs) {
|
IconButton(onClick = onClearLogs) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Trash,
|
painter = TelegramIcons.Delete,
|
||||||
contentDescription = "Clear logs",
|
contentDescription = "Clear logs",
|
||||||
tint = secondaryTextColor.copy(alpha = 0.6f),
|
tint = secondaryTextColor.copy(alpha = 0.6f),
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ import com.rosetta.messenger.ui.utils.SystemBarsStyleUtils
|
|||||||
import com.yalantis.ucrop.UCrop
|
import com.yalantis.ucrop.UCrop
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import ja.burhanrashid52.photoeditor.PhotoEditor
|
import ja.burhanrashid52.photoeditor.PhotoEditor
|
||||||
import ja.burhanrashid52.photoeditor.PhotoEditorView
|
import ja.burhanrashid52.photoeditor.PhotoEditorView
|
||||||
import ja.burhanrashid52.photoeditor.SaveSettings
|
import ja.burhanrashid52.photoeditor.SaveSettings
|
||||||
@@ -472,7 +473,7 @@ fun ImageEditorScreen(
|
|||||||
modifier = Modifier.align(Alignment.CenterStart)
|
modifier = Modifier.align(Alignment.CenterStart)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Close",
|
contentDescription = "Close",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(28.dp)
|
modifier = Modifier.size(28.dp)
|
||||||
@@ -1102,7 +1103,7 @@ private fun TelegramCaptionBar(
|
|||||||
modifier = Modifier.size(32.dp)
|
modifier = Modifier.size(32.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
if (showEmojiPicker) TablerIcons.Keyboard else TablerIcons.MoodSmile,
|
painter = if (showEmojiPicker) TelegramIcons.Keyboard else TelegramIcons.Smile,
|
||||||
contentDescription = if (showEmojiPicker) "Keyboard" else "Emoji",
|
contentDescription = if (showEmojiPicker) "Keyboard" else "Emoji",
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(26.dp)
|
modifier = Modifier.size(26.dp)
|
||||||
@@ -1699,7 +1700,7 @@ fun MultiImageEditorScreen(
|
|||||||
modifier = Modifier.align(Alignment.CenterStart)
|
modifier = Modifier.align(Alignment.CenterStart)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Close",
|
contentDescription = "Close",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(28.dp)
|
modifier = Modifier.size(28.dp)
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ import coil.compose.AsyncImage
|
|||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
import com.rosetta.messenger.ui.components.AppleEmojiTextField
|
import com.rosetta.messenger.ui.components.AppleEmojiTextField
|
||||||
import com.rosetta.messenger.ui.components.KeyboardHeightProvider
|
import com.rosetta.messenger.ui.components.KeyboardHeightProvider
|
||||||
@@ -597,7 +598,7 @@ fun MediaPickerBottomSheet(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Photo,
|
painter = TelegramIcons.Photos,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = secondaryTextColor,
|
tint = secondaryTextColor,
|
||||||
modifier = Modifier.size(64.dp)
|
modifier = Modifier.size(64.dp)
|
||||||
@@ -862,7 +863,7 @@ private fun MediaPickerHeader(
|
|||||||
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 8.dp)
|
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 8.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Send,
|
painter = TelegramIcons.Send,
|
||||||
contentDescription = "Send",
|
contentDescription = "Send",
|
||||||
modifier = Modifier.size(18.dp),
|
modifier = Modifier.size(18.dp),
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
@@ -897,7 +898,7 @@ private fun QuickActionsRow(
|
|||||||
) {
|
) {
|
||||||
// Camera button
|
// Camera button
|
||||||
QuickActionButton(
|
QuickActionButton(
|
||||||
icon = TablerIcons.Camera,
|
icon = TelegramIcons.Camera,
|
||||||
label = "Camera",
|
label = "Camera",
|
||||||
backgroundColor = PrimaryBlue,
|
backgroundColor = PrimaryBlue,
|
||||||
iconColor = Color.White,
|
iconColor = Color.White,
|
||||||
@@ -907,7 +908,7 @@ private fun QuickActionsRow(
|
|||||||
|
|
||||||
// Avatar button
|
// Avatar button
|
||||||
QuickActionButton(
|
QuickActionButton(
|
||||||
icon = TablerIcons.User,
|
icon = TelegramIcons.Contact,
|
||||||
label = "Avatar",
|
label = "Avatar",
|
||||||
backgroundColor = buttonColor,
|
backgroundColor = buttonColor,
|
||||||
iconColor = iconColor,
|
iconColor = iconColor,
|
||||||
@@ -917,7 +918,7 @@ private fun QuickActionsRow(
|
|||||||
|
|
||||||
// File button
|
// File button
|
||||||
QuickActionButton(
|
QuickActionButton(
|
||||||
icon = TablerIcons.File,
|
icon = TelegramIcons.File,
|
||||||
label = "File",
|
label = "File",
|
||||||
backgroundColor = buttonColor,
|
backgroundColor = buttonColor,
|
||||||
iconColor = iconColor,
|
iconColor = iconColor,
|
||||||
@@ -929,7 +930,7 @@ private fun QuickActionsRow(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun QuickActionButton(
|
private fun QuickActionButton(
|
||||||
icon: androidx.compose.ui.graphics.vector.ImageVector,
|
icon: androidx.compose.ui.graphics.painter.Painter,
|
||||||
label: String,
|
label: String,
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
iconColor: Color,
|
iconColor: Color,
|
||||||
@@ -969,7 +970,7 @@ private fun QuickActionButton(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
painter = icon,
|
||||||
contentDescription = label,
|
contentDescription = label,
|
||||||
tint = iconColor,
|
tint = iconColor,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1125,7 +1126,7 @@ private fun CameraGridItem(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Camera,
|
painter = TelegramIcons.Camera,
|
||||||
contentDescription = "Camera",
|
contentDescription = "Camera",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -1143,7 +1144,7 @@ private fun CameraGridItem(
|
|||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Camera,
|
painter = TelegramIcons.Camera,
|
||||||
contentDescription = "Camera",
|
contentDescription = "Camera",
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -1262,7 +1263,7 @@ private fun MediaGridItem(
|
|||||||
) {
|
) {
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -1586,7 +1587,7 @@ fun PhotoPreviewWithCaptionScreen(
|
|||||||
modifier = Modifier.align(Alignment.CenterStart)
|
modifier = Modifier.align(Alignment.CenterStart)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Close",
|
contentDescription = "Close",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(28.dp)
|
modifier = Modifier.size(28.dp)
|
||||||
@@ -1634,7 +1635,7 @@ fun PhotoPreviewWithCaptionScreen(
|
|||||||
label = "emojiIcon"
|
label = "emojiIcon"
|
||||||
) { isEmoji ->
|
) { isEmoji ->
|
||||||
Icon(
|
Icon(
|
||||||
if (isEmoji) TablerIcons.Keyboard else TablerIcons.MoodSmile,
|
painter = if (isEmoji) TelegramIcons.Keyboard else TelegramIcons.Smile,
|
||||||
contentDescription = if (isEmoji) "Keyboard" else "Emoji",
|
contentDescription = if (isEmoji) "Keyboard" else "Emoji",
|
||||||
tint = Color.White.copy(alpha = 0.7f),
|
tint = Color.White.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(26.dp)
|
modifier = Modifier.size(26.dp)
|
||||||
@@ -1676,7 +1677,7 @@ fun PhotoPreviewWithCaptionScreen(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Send,
|
painter = TelegramIcons.Send,
|
||||||
contentDescription = "Send",
|
contentDescription = "Send",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
|||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import compose.icons.TablerIcons
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.tablericons.*
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -272,7 +271,7 @@ fun MessageInputBar(
|
|||||||
horizontalArrangement = Arrangement.Center
|
horizontalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Ban,
|
painter = TelegramIcons.Block,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color(0xFFFF6B6B),
|
tint = Color(0xFFFF6B6B),
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
@@ -419,7 +418,7 @@ fun MessageInputBar(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Cancel",
|
contentDescription = "Cancel",
|
||||||
tint = if (isDarkTheme) Color.White.copy(alpha = 0.5f)
|
tint = if (isDarkTheme) Color.White.copy(alpha = 0.5f)
|
||||||
else Color.Black.copy(alpha = 0.4f),
|
else Color.Black.copy(alpha = 0.4f),
|
||||||
@@ -442,7 +441,7 @@ fun MessageInputBar(
|
|||||||
modifier = Modifier.size(40.dp)
|
modifier = Modifier.size(40.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.Paperclip,
|
painter = TelegramIcons.Attach,
|
||||||
contentDescription = "Attach",
|
contentDescription = "Attach",
|
||||||
tint = if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.6f)
|
tint = if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.6f)
|
||||||
else Color(0xFF8E8E93).copy(alpha = 0.6f),
|
else Color(0xFF8E8E93).copy(alpha = 0.6f),
|
||||||
@@ -485,8 +484,8 @@ fun MessageInputBar(
|
|||||||
modifier = Modifier.size(40.dp)
|
modifier = Modifier.size(40.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
if (showEmojiPicker) TablerIcons.Keyboard
|
painter = if (showEmojiPicker) TelegramIcons.Keyboard
|
||||||
else TablerIcons.MoodSmile,
|
else TelegramIcons.Smile,
|
||||||
contentDescription = "Emoji",
|
contentDescription = "Emoji",
|
||||||
tint = if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.6f)
|
tint = if (isDarkTheme) Color(0xFF8E8E93).copy(alpha = 0.6f)
|
||||||
else Color(0xFF8E8E93).copy(alpha = 0.6f),
|
else Color(0xFF8E8E93).copy(alpha = 0.6f),
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package com.rosetta.messenger.ui.icons
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import com.rosetta.messenger.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Centralized Telegram icon provider.
|
||||||
|
* Maps to Telegram's native PNG drawable resources.
|
||||||
|
* Use with Icon(painter = TelegramIcons.ArrowBack, ...)
|
||||||
|
*/
|
||||||
|
object TelegramIcons {
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 🧭 NAVIGATION
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val ArrowBack: Painter @Composable get() = painterResource(R.drawable.msg_arrow_back)
|
||||||
|
val Close: Painter @Composable get() = painterResource(R.drawable.msg_close)
|
||||||
|
val ChevronDown: Painter @Composable get() = painterResource(R.drawable.ic_arrow_drop_down)
|
||||||
|
val ChevronRight: Painter @Composable get() = painterResource(R.drawable.msg_arrowright)
|
||||||
|
val More: Painter @Composable get() = painterResource(R.drawable.ic_ab_other)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Done: Painter @Composable get() = painterResource(R.drawable.ic_ab_done)
|
||||||
|
val Add: Painter @Composable get() = painterResource(R.drawable.msg_add)
|
||||||
|
val Edit: Painter @Composable get() = painterResource(R.drawable.msg_edit)
|
||||||
|
val Delete: Painter @Composable get() = painterResource(R.drawable.msg_delete)
|
||||||
|
val Reply: Painter @Composable get() = painterResource(R.drawable.ic_ab_reply)
|
||||||
|
val Retry: Painter @Composable get() = painterResource(R.drawable.msg_retry)
|
||||||
|
val Send: Painter @Composable get() = painterResource(R.drawable.msg_send)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 🔔 NOTIFICATIONS
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Notifications: Painter @Composable get() = painterResource(R.drawable.msg_notifications)
|
||||||
|
val Mute: Painter @Composable get() = painterResource(R.drawable.msg_mute)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 📌 CHAT ACTIONS
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Pin: Painter @Composable get() = painterResource(R.drawable.msg_pin)
|
||||||
|
val Unpin: Painter @Composable get() = painterResource(R.drawable.msg_unpin)
|
||||||
|
val Block: Painter @Composable get() = painterResource(R.drawable.msg_block)
|
||||||
|
val Message: Painter @Composable get() = painterResource(R.drawable.msg_message)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 🔒 SECURITY
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Secret: Painter @Composable get() = painterResource(R.drawable.msg_secret)
|
||||||
|
val Unlock: Painter @Composable get() = painterResource(R.drawable.menu_unlock)
|
||||||
|
val Fingerprint: Painter @Composable get() = painterResource(R.drawable.fingerprint)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 📷 MEDIA
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Camera: Painter @Composable get() = painterResource(R.drawable.msg_camera)
|
||||||
|
val AddPhoto: Painter @Composable get() = painterResource(R.drawable.msg_addphoto)
|
||||||
|
val Photos: Painter @Composable get() = painterResource(R.drawable.msg_photos)
|
||||||
|
val File: Painter @Composable get() = painterResource(R.drawable.msg_sendfile)
|
||||||
|
val Attach: Painter @Composable get() = painterResource(R.drawable.input_attach)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 😊 INPUT
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Smile: Painter @Composable get() = painterResource(R.drawable.input_smile)
|
||||||
|
val Keyboard: Painter @Composable get() = painterResource(R.drawable.input_keyboard)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// ⚙️ SETTINGS
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Palette: Painter @Composable get() = painterResource(R.drawable.msg_palette)
|
||||||
|
val Theme: Painter @Composable get() = painterResource(R.drawable.msg_theme)
|
||||||
|
val Customize: Painter @Composable get() = painterResource(R.drawable.msg_customize)
|
||||||
|
val Leave: Painter @Composable get() = painterResource(R.drawable.msg_leave)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 👤 CONTACTS
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Contact: Painter @Composable get() = painterResource(R.drawable.msg_contact)
|
||||||
|
val AddContact: Painter @Composable get() = painterResource(R.drawable.msg_addcontact)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// ℹ️ STATUS & INFO
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val Clock: Painter @Composable get() = painterResource(R.drawable.msg_autodelete)
|
||||||
|
val Warning: Painter @Composable get() = painterResource(R.drawable.msg_warning)
|
||||||
|
val Info: Painter @Composable get() = painterResource(R.drawable.msg_info)
|
||||||
|
val Views: Painter @Composable get() = painterResource(R.drawable.msg_views)
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -28,6 +29,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -55,6 +57,16 @@ fun AppearanceScreen(
|
|||||||
accountName: String = "",
|
accountName: String = "",
|
||||||
avatarRepository: AvatarRepository? = null
|
avatarRepository: AvatarRepository? = null
|
||||||
) {
|
) {
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||||
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
|
val secondaryTextColor = if (isDarkTheme) Color(0xFF8E8E93) else Color(0xFF666666)
|
||||||
@@ -101,7 +113,7 @@ fun AppearanceScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
@@ -441,7 +453,7 @@ private fun ColorCircleItem(
|
|||||||
|
|
||||||
val borderColor by animateColorAsState(
|
val borderColor by animateColorAsState(
|
||||||
targetValue = if (isSelected) {
|
targetValue = if (isSelected) {
|
||||||
Color.White
|
if (isDarkTheme) Color.White else Color(0xFF222222)
|
||||||
} else {
|
} else {
|
||||||
Color.Transparent
|
Color.Transparent
|
||||||
},
|
},
|
||||||
@@ -456,7 +468,7 @@ private fun ColorCircleItem(
|
|||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.border(
|
.border(
|
||||||
width = if (isSelected) 2.5.dp else 0.5.dp,
|
width = if (isSelected) 2.5.dp else 0.5.dp,
|
||||||
color = if (isSelected) borderColor else Color.White.copy(alpha = 0.12f),
|
color = if (isSelected) borderColor else if (isDarkTheme) Color.White.copy(alpha = 0.12f) else Color.Black.copy(alpha = 0.12f),
|
||||||
shape = CircleShape
|
shape = CircleShape
|
||||||
)
|
)
|
||||||
.clickable(onClick = onClick),
|
.clickable(onClick = onClick),
|
||||||
@@ -509,7 +521,7 @@ private fun ColorCircleItem(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = "Selected",
|
contentDescription = "Selected",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.airbnb.lottie.compose.*
|
|||||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
// Auth colors
|
// Auth colors
|
||||||
@@ -82,6 +83,14 @@ fun BiometricEnableScreen(
|
|||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val view = LocalView.current
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to hide keyboard
|
// Function to hide keyboard
|
||||||
fun hideKeyboard() {
|
fun hideKeyboard() {
|
||||||
@@ -141,7 +150,7 @@ fun BiometricEnableScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack, enabled = !isLoading) {
|
IconButton(onClick = onBack, enabled = !isLoading) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = textColor.copy(alpha = 0.6f)
|
tint = textColor.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
@@ -312,7 +321,7 @@ fun BiometricEnableScreen(
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.AlertCircle,
|
painter = TelegramIcons.Warning,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = errorRed,
|
tint = errorRed,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
@@ -377,7 +386,7 @@ fun BiometricEnableScreen(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Fingerprint,
|
painter = TelegramIcons.Fingerprint,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
)
|
)
|
||||||
@@ -408,7 +417,7 @@ fun BiometricEnableScreen(
|
|||||||
verticalAlignment = Alignment.Top
|
verticalAlignment = Alignment.Top
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ShieldLock,
|
painter = TelegramIcons.Secret,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ import androidx.compose.foundation.pager.rememberPagerState
|
|||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
|
||||||
import androidx.compose.material.icons.outlined.Block
|
import androidx.compose.material.icons.outlined.Block
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
@@ -43,6 +41,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.clipToBounds
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
@@ -62,6 +61,7 @@ import androidx.compose.ui.text.style.TextDecoration
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.unit.Velocity
|
import androidx.compose.ui.unit.Velocity
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -93,6 +93,7 @@ import com.rosetta.messenger.ui.components.metaball.ProfileMetaballEffect
|
|||||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
import com.rosetta.messenger.utils.AttachmentFileManager
|
import com.rosetta.messenger.utils.AttachmentFileManager
|
||||||
import com.rosetta.messenger.utils.AvatarFileManager
|
import com.rosetta.messenger.utils.AvatarFileManager
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -220,6 +221,10 @@ fun OtherProfileScreen(
|
|||||||
val chatsListViewModel: ChatsListViewModel = viewModel()
|
val chatsListViewModel: ChatsListViewModel = viewModel()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// 🔕 Mute state
|
||||||
|
val preferencesManager = remember { com.rosetta.messenger.data.PreferencesManager(context) }
|
||||||
|
var notificationsEnabled by remember { mutableStateOf(true) }
|
||||||
|
|
||||||
// 🔥 Загружаем статус блокировки при открытии экрана
|
// 🔥 Загружаем статус блокировки при открытии экрана
|
||||||
LaunchedEffect(user.publicKey) { isBlocked = chatsListViewModel.isUserBlocked(user.publicKey) }
|
LaunchedEffect(user.publicKey) { isBlocked = chatsListViewModel.isUserBlocked(user.publicKey) }
|
||||||
|
|
||||||
@@ -244,6 +249,14 @@ fun OtherProfileScreen(
|
|||||||
remember(currentUserPublicKey) { currentUserPublicKey.trim() }
|
remember(currentUserPublicKey) { currentUserPublicKey.trim() }
|
||||||
val activeAccountPrivateKey =
|
val activeAccountPrivateKey =
|
||||||
remember(currentUserPrivateKey) { currentUserPrivateKey.trim() }
|
remember(currentUserPrivateKey) { currentUserPrivateKey.trim() }
|
||||||
|
|
||||||
|
// 🔕 Load mute state from preferences
|
||||||
|
LaunchedEffect(activeAccountPublicKey, user.publicKey) {
|
||||||
|
if (activeAccountPublicKey.isNotBlank()) {
|
||||||
|
notificationsEnabled = !preferencesManager.isChatMuted(activeAccountPublicKey, user.publicKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val dialogKey =
|
val dialogKey =
|
||||||
remember(activeAccountPublicKey, user.publicKey) {
|
remember(activeAccountPublicKey, user.publicKey) {
|
||||||
if (activeAccountPublicKey.isBlank()) {
|
if (activeAccountPublicKey.isBlank()) {
|
||||||
@@ -522,14 +535,14 @@ fun OtherProfileScreen(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// 📋 ACCOUNT SECTION
|
// 📋 INFORMATION SECTION — первый элемент
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
TelegramSectionTitle(title = "Account", isDarkTheme = isDarkTheme)
|
TelegramSectionTitle(
|
||||||
|
title = "Information",
|
||||||
|
isDarkTheme = isDarkTheme,
|
||||||
|
color = PrimaryBlue
|
||||||
|
)
|
||||||
|
|
||||||
if (user.username.isNotBlank()) {
|
if (user.username.isNotBlank()) {
|
||||||
TelegramCopyField(
|
TelegramCopyField(
|
||||||
@@ -538,6 +551,12 @@ fun OtherProfileScreen(
|
|||||||
label = "Username",
|
label = "Username",
|
||||||
isDarkTheme = isDarkTheme
|
isDarkTheme = isDarkTheme
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Divider(
|
||||||
|
color = if (isDarkTheme) Color(0xFF3A3A3A) else Color(0xFFE0E0E0),
|
||||||
|
thickness = 0.5.dp,
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
TelegramCopyField(
|
TelegramCopyField(
|
||||||
@@ -547,11 +566,21 @@ fun OtherProfileScreen(
|
|||||||
isDarkTheme = isDarkTheme
|
isDarkTheme = isDarkTheme
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// Разделитель секций
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(8.dp)
|
||||||
|
.background(if (isDarkTheme) Color(0xFF0F0F0F) else Color(0xFFF0F0F0))
|
||||||
|
)
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// ✉️ WRITE MESSAGE BUTTON
|
// ✉️ WRITE MESSAGE BUTTON
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@@ -573,7 +602,7 @@ fun OtherProfileScreen(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
TablerIcons.MessageCircle2,
|
painter = TelegramIcons.Message,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(20.dp),
|
modifier = Modifier.size(20.dp),
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
@@ -588,13 +617,32 @@ fun OtherProfileScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// 📚 SHARED CONTENT
|
// 🔔 NOTIFICATIONS SECTION
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
TelegramSectionTitle(title = "Shared", isDarkTheme = isDarkTheme)
|
TelegramToggleItem(
|
||||||
|
icon = if (notificationsEnabled) TelegramIcons.Notifications else TelegramIcons.Mute,
|
||||||
|
title = "Notifications",
|
||||||
|
subtitle = if (notificationsEnabled) "On" else "Off",
|
||||||
|
isEnabled = notificationsEnabled,
|
||||||
|
onToggle = {
|
||||||
|
notificationsEnabled = !notificationsEnabled
|
||||||
|
coroutineScope.launch {
|
||||||
|
preferencesManager.setChatMuted(
|
||||||
|
activeAccountPublicKey,
|
||||||
|
user.publicKey,
|
||||||
|
!notificationsEnabled
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
isDarkTheme = isDarkTheme
|
||||||
|
)
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 📚 SHARED CONTENT (без разделителя — сразу табы)
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
OtherProfileSharedTabs(
|
OtherProfileSharedTabs(
|
||||||
selectedTab = selectedTab,
|
selectedTab = selectedTab,
|
||||||
onTabSelected = { tab ->
|
onTabSelected = { tab ->
|
||||||
@@ -1202,7 +1250,7 @@ private fun OtherProfileActionButtons(
|
|||||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||||
) {
|
) {
|
||||||
OtherProfileActionButton(
|
OtherProfileActionButton(
|
||||||
icon = TablerIcons.MessageCircle2,
|
icon = TelegramIcons.Message,
|
||||||
title = "Message",
|
title = "Message",
|
||||||
subtitle = "Open chat",
|
subtitle = "Open chat",
|
||||||
accent = PrimaryBlue,
|
accent = PrimaryBlue,
|
||||||
@@ -1211,7 +1259,7 @@ private fun OtherProfileActionButtons(
|
|||||||
onClick = onMessageClick
|
onClick = onMessageClick
|
||||||
)
|
)
|
||||||
OtherProfileActionButton(
|
OtherProfileActionButton(
|
||||||
icon = if (isMuted) TablerIcons.BellOff else TablerIcons.BellRinging2,
|
icon = if (isMuted) TelegramIcons.Mute else TelegramIcons.Notifications,
|
||||||
title = if (isMuted) "Muted" else "Mute",
|
title = if (isMuted) "Muted" else "Mute",
|
||||||
subtitle = if (isMuted) "Tap to unmute" else "Silence notifications",
|
subtitle = if (isMuted) "Tap to unmute" else "Silence notifications",
|
||||||
accent =
|
accent =
|
||||||
@@ -1229,7 +1277,7 @@ private fun OtherProfileActionButtons(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun OtherProfileActionButton(
|
private fun OtherProfileActionButton(
|
||||||
icon: ImageVector,
|
icon: Painter,
|
||||||
title: String,
|
title: String,
|
||||||
subtitle: String,
|
subtitle: String,
|
||||||
accent: Color,
|
accent: Color,
|
||||||
@@ -1260,7 +1308,7 @@ private fun OtherProfileActionButton(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
painter = icon,
|
||||||
contentDescription = title,
|
contentDescription = title,
|
||||||
tint = accent,
|
tint = accent,
|
||||||
modifier = Modifier.size(19.dp)
|
modifier = Modifier.size(19.dp)
|
||||||
@@ -1504,7 +1552,7 @@ private fun OtherProfileFileList(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.File,
|
painter = TelegramIcons.File,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = PrimaryBlue,
|
tint = PrimaryBlue,
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
@@ -1661,8 +1709,11 @@ private fun CollapsingOtherProfileHeader(
|
|||||||
val avatarFontSize = androidx.compose.ui.unit.lerp(40.sp, 12.sp, collapseProgress)
|
val avatarFontSize = androidx.compose.ui.unit.lerp(40.sp, 12.sp, collapseProgress)
|
||||||
|
|
||||||
// Text animation - always centered
|
// Text animation - always centered
|
||||||
val textDefaultY = expandedHeight - 48.dp
|
val textDefaultY = expandedHeight - 70.dp
|
||||||
val textCollapsedY = statusBarHeight + COLLAPSED_HEADER_HEIGHT_OTHER / 2
|
// Collapsed: center text block vertically in collapsed header
|
||||||
|
// Text block is ~42dp tall (name 18sp ~22dp + 2dp spacer + online 13sp ~18dp)
|
||||||
|
val textBlockHeight = 42.dp
|
||||||
|
val textCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT_OTHER - textBlockHeight) / 2
|
||||||
val textY = androidx.compose.ui.unit.lerp(textDefaultY, textCollapsedY, collapseProgress)
|
val textY = androidx.compose.ui.unit.lerp(textDefaultY, textCollapsedY, collapseProgress)
|
||||||
|
|
||||||
val nameFontSize = androidx.compose.ui.unit.lerp(24.sp, 18.sp, collapseProgress)
|
val nameFontSize = androidx.compose.ui.unit.lerp(24.sp, 18.sp, collapseProgress)
|
||||||
@@ -1673,7 +1724,19 @@ private fun CollapsingOtherProfileHeader(
|
|||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
val textColor = Color.White
|
val textColor = Color.White
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 🔙 BUTTONS Y - At top when expanded, centered when collapsed
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val buttonsExpandedY = statusBarHeight + 8.dp
|
||||||
|
val buttonsCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT_OTHER - 48.dp) / 2
|
||||||
|
val buttonsY = androidx.compose.ui.unit.lerp(buttonsExpandedY, buttonsCollapsedY, collapseProgress)
|
||||||
|
|
||||||
Box(modifier = Modifier.fillMaxWidth().height(headerHeight).clipToBounds()) {
|
Box(modifier = Modifier.fillMaxWidth().height(headerHeight).clipToBounds()) {
|
||||||
|
// Solid opaque background floor — prevents content from bleeding through
|
||||||
|
Box(modifier = Modifier.matchParentSize().background(
|
||||||
|
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFEFEFF4)
|
||||||
|
))
|
||||||
|
|
||||||
// Expansion fraction — computed early so blur can fade during expansion
|
// Expansion fraction — computed early so blur can fade during expansion
|
||||||
val expandFractionEarly = expansionProgress.coerceIn(0f, 1f)
|
val expandFractionEarly = expansionProgress.coerceIn(0f, 1f)
|
||||||
val blurAlpha = (1f - expandFractionEarly * 2.5f).coerceIn(0f, 1f)
|
val blurAlpha = (1f - expandFractionEarly * 2.5f).coerceIn(0f, 1f)
|
||||||
@@ -1695,6 +1758,28 @@ private fun CollapsingOtherProfileHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
// 🌅 BOTTOM GRADIENT — плавно исчезает когда аватарка раскрывается
|
||||||
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val gradientAlpha = (1f - expandFractionEarly * 1.2f).coerceIn(0f, 1f)
|
||||||
|
if (gradientAlpha > 0.01f) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(80.dp)
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.graphicsLayer { alpha = gradientAlpha }
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Transparent,
|
||||||
|
Color.Black.copy(alpha = 0.35f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// 👤 AVATAR — Telegram-style expansion on pull-down
|
// 👤 AVATAR — Telegram-style expansion on pull-down
|
||||||
// При скролле вверх: metaball merge с Dynamic Island
|
// При скролле вверх: metaball merge с Dynamic Island
|
||||||
@@ -1795,19 +1880,56 @@ private fun CollapsingOtherProfileHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gradient overlays when avatar is expanded
|
||||||
|
if (expansionAvatarAlpha > 0.01f) {
|
||||||
|
// Top gradient
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp)
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.graphicsLayer { alpha = expandFraction.coerceIn(0f, 1f) }
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Black.copy(alpha = 0.6f),
|
||||||
|
Color.Transparent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// Bottom gradient
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp)
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.graphicsLayer { alpha = expandFraction.coerceIn(0f, 1f) }
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Transparent,
|
||||||
|
Color.Black.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// 🔙 BACK BUTTON
|
// 🔙 BACK BUTTON - At top when expanded, centered when collapsed
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.padding(top = statusBarHeight)
|
Modifier
|
||||||
.padding(start = 4.dp, top = 4.dp)
|
.align(Alignment.TopStart)
|
||||||
|
.offset(x = 4.dp, y = buttonsY)
|
||||||
.size(48.dp),
|
.size(48.dp),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack, modifier = Modifier.size(48.dp)) {
|
IconButton(onClick = onBack, modifier = Modifier.size(48.dp)) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.ArrowBack,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1816,19 +1938,17 @@ private fun CollapsingOtherProfileHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// ⋮ MENU BUTTON (top right corner)
|
// ⋮ MENU BUTTON - At top when expanded, centered when collapsed
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.align(Alignment.TopEnd)
|
Modifier.align(Alignment.TopEnd)
|
||||||
.padding(top = statusBarHeight)
|
.offset(x = -4.dp, y = buttonsY),
|
||||||
.padding(end = 4.dp, top = 4.dp)
|
|
||||||
.size(48.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = { onAvatarMenuChange(true) }, modifier = Modifier.size(48.dp)) {
|
IconButton(onClick = { onAvatarMenuChange(true) }, modifier = Modifier.size(48.dp)) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.MoreVert,
|
painter = TelegramIcons.More,
|
||||||
contentDescription = "Profile menu",
|
contentDescription = "Profile menu",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1857,17 +1977,7 @@ private fun CollapsingOtherProfileHeader(
|
|||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.align(Alignment.TopCenter).offset(y = textY).graphicsLayer {
|
Modifier.align(Alignment.TopCenter).offset(y = textY),
|
||||||
val centerOffsetY =
|
|
||||||
with(density) {
|
|
||||||
androidx.compose
|
|
||||||
.ui
|
|
||||||
.unit
|
|
||||||
.lerp(24.dp, 18.dp, collapseProgress)
|
|
||||||
.toPx()
|
|
||||||
}
|
|
||||||
translationY = -centerOffsetY
|
|
||||||
},
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
// Name + Verified Badge
|
// Name + Verified Badge
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -25,6 +27,16 @@ fun ProfileLogsScreen(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onClearLogs: () -> Unit
|
onClearLogs: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||||
val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
|
val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
|
||||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||||
@@ -63,7 +75,7 @@ fun ProfileLogsScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = textColor
|
tint = textColor
|
||||||
)
|
)
|
||||||
@@ -79,7 +91,7 @@ fun ProfileLogsScreen(
|
|||||||
)
|
)
|
||||||
IconButton(onClick = onClearLogs) {
|
IconButton(onClick = onClearLogs) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Trash,
|
painter = TelegramIcons.Delete,
|
||||||
contentDescription = "Clear logs",
|
contentDescription = "Clear logs",
|
||||||
tint = secondaryTextColor
|
tint = secondaryTextColor
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ import androidx.compose.ui.window.PopupProperties
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import compose.icons.TablerIcons
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.tablericons.*
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -292,7 +291,7 @@ fun ProfilePhotoPicker(
|
|||||||
modifier = Modifier.align(Alignment.CenterStart)
|
modifier = Modifier.align(Alignment.CenterStart)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.X,
|
painter = TelegramIcons.Close,
|
||||||
contentDescription = "Close",
|
contentDescription = "Close",
|
||||||
tint = textColor,
|
tint = textColor,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -350,7 +349,7 @@ fun ProfilePhotoPicker(
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Photo,
|
painter = TelegramIcons.Photos,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = textColor.copy(alpha = 0.4f),
|
tint = textColor.copy(alpha = 0.4f),
|
||||||
modifier = Modifier.size(64.dp)
|
modifier = Modifier.size(64.dp)
|
||||||
@@ -501,7 +500,7 @@ private fun PermissionRequest(
|
|||||||
modifier = Modifier.padding(32.dp)
|
modifier = Modifier.padding(32.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Photo,
|
painter = TelegramIcons.Photos,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = textColor.copy(alpha = 0.5f),
|
tint = textColor.copy(alpha = 0.5f),
|
||||||
modifier = Modifier.size(64.dp)
|
modifier = Modifier.size(64.dp)
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import androidx.compose.ui.platform.LocalConfiguration
|
|||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -74,6 +75,11 @@ import java.util.Locale
|
|||||||
import com.rosetta.messenger.utils.ImageCropHelper
|
import com.rosetta.messenger.utils.ImageCropHelper
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import com.rosetta.messenger.R
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
|
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
@@ -278,6 +284,16 @@ fun ProfileScreen(
|
|||||||
dialogDao: com.rosetta.messenger.database.DialogDao? = null,
|
dialogDao: com.rosetta.messenger.database.DialogDao? = null,
|
||||||
backgroundBlurColorId: String = "avatar"
|
backgroundBlurColorId: String = "avatar"
|
||||||
) {
|
) {
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = false
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val activity = context as? FragmentActivity
|
val activity = context as? FragmentActivity
|
||||||
val biometricManager = remember { BiometricAuthManager(context) }
|
val biometricManager = remember { BiometricAuthManager(context) }
|
||||||
@@ -817,7 +833,7 @@ fun ProfileScreen(
|
|||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
TelegramToggleItem(
|
TelegramToggleItem(
|
||||||
icon = TablerIcons.Bell,
|
icon = TelegramIcons.Notifications,
|
||||||
title = "Push Notifications",
|
title = "Push Notifications",
|
||||||
isEnabled = notificationsEnabled,
|
isEnabled = notificationsEnabled,
|
||||||
onToggle = {
|
onToggle = {
|
||||||
@@ -837,7 +853,7 @@ fun ProfileScreen(
|
|||||||
TelegramSectionTitle(title = "Settings", isDarkTheme = isDarkTheme)
|
TelegramSectionTitle(title = "Settings", isDarkTheme = isDarkTheme)
|
||||||
|
|
||||||
TelegramSettingsItem(
|
TelegramSettingsItem(
|
||||||
icon = TablerIcons.Palette,
|
icon = TelegramIcons.Theme,
|
||||||
title = "Theme",
|
title = "Theme",
|
||||||
onClick = onNavigateToTheme,
|
onClick = onNavigateToTheme,
|
||||||
isDarkTheme = isDarkTheme,
|
isDarkTheme = isDarkTheme,
|
||||||
@@ -845,7 +861,7 @@ fun ProfileScreen(
|
|||||||
)
|
)
|
||||||
|
|
||||||
TelegramSettingsItem(
|
TelegramSettingsItem(
|
||||||
icon = TablerIcons.Brush,
|
icon = TelegramIcons.Customize,
|
||||||
title = "Appearance",
|
title = "Appearance",
|
||||||
onClick = onNavigateToAppearance,
|
onClick = onNavigateToAppearance,
|
||||||
isDarkTheme = isDarkTheme,
|
isDarkTheme = isDarkTheme,
|
||||||
@@ -853,7 +869,7 @@ fun ProfileScreen(
|
|||||||
)
|
)
|
||||||
|
|
||||||
TelegramSettingsItem(
|
TelegramSettingsItem(
|
||||||
icon = TablerIcons.Lock,
|
icon = TelegramIcons.Secret,
|
||||||
title = "Safety",
|
title = "Safety",
|
||||||
onClick = onNavigateToSafety,
|
onClick = onNavigateToSafety,
|
||||||
isDarkTheme = isDarkTheme,
|
isDarkTheme = isDarkTheme,
|
||||||
@@ -863,7 +879,7 @@ fun ProfileScreen(
|
|||||||
// Biometric settings (only show if available)
|
// Biometric settings (only show if available)
|
||||||
if (biometricAvailable is BiometricAvailability.Available && activity != null) {
|
if (biometricAvailable is BiometricAvailability.Available && activity != null) {
|
||||||
TelegramSettingsItem(
|
TelegramSettingsItem(
|
||||||
icon = TablerIcons.Fingerprint,
|
icon = TelegramIcons.Fingerprint,
|
||||||
title = "Biometric Authentication",
|
title = "Biometric Authentication",
|
||||||
onClick = {
|
onClick = {
|
||||||
onNavigateToBiometric()
|
onNavigateToBiometric()
|
||||||
@@ -972,10 +988,9 @@ fun ProfileScreen(
|
|||||||
// Positioned at bottom-right of header, half overlapping content area
|
// Positioned at bottom-right of header, half overlapping content area
|
||||||
// Fades out when collapsed or when avatar is expanded
|
// Fades out when collapsed or when avatar is expanded
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
val cameraButtonAlpha = (1f - collapseProgress * 2.5f).coerceIn(0f, 1f) *
|
val cameraButtonSize = 60.dp
|
||||||
(1f - expansionProgress * 4f).coerceIn(0f, 1f)
|
val cameraButtonAlpha = (1f - collapseProgress * 2f).coerceIn(0f, 1f)
|
||||||
if (cameraButtonAlpha > 0.01f) {
|
if (cameraButtonAlpha > 0.01f) {
|
||||||
val cameraButtonSize = 52.dp
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.TopEnd)
|
.align(Alignment.TopEnd)
|
||||||
@@ -991,15 +1006,15 @@ fun ProfileScreen(
|
|||||||
clip = false
|
clip = false
|
||||||
)
|
)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(Color.White)
|
.background(if (isDarkTheme) Color.White else PrimaryBlue)
|
||||||
.clickable { showPhotoPicker = true },
|
.clickable { showPhotoPicker = true },
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.CameraPlus,
|
painter = TelegramIcons.AddPhoto,
|
||||||
contentDescription = "Change avatar",
|
contentDescription = "Change avatar",
|
||||||
tint = Color(0xFF8E8E93),
|
tint = if (isDarkTheme) Color(0xFF8E8E93) else Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(26.dp).offset(x = 2.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1089,7 +1104,10 @@ private fun CollapsingProfileHeader(
|
|||||||
// 📝 TEXT - внизу header зоны, внутри блока
|
// 📝 TEXT - внизу header зоны, внутри блока
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
val textDefaultY = expandedHeight - 70.dp // Ближе к аватарке
|
val textDefaultY = expandedHeight - 70.dp // Ближе к аватарке
|
||||||
val textCollapsedY = statusBarHeight + COLLAPSED_HEADER_HEIGHT / 2
|
// Collapsed: center text block vertically in collapsed header
|
||||||
|
// Text block is ~35dp tall (name 18sp + 2dp spacer + online 13sp)
|
||||||
|
val textBlockHeight = 35.dp
|
||||||
|
val textCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT - textBlockHeight) / 2
|
||||||
|
|
||||||
// Текст меняет позицию только при collapse, НЕ при overscroll
|
// Текст меняет позицию только при collapse, НЕ при overscroll
|
||||||
val textY = androidx.compose.ui.unit.lerp(textDefaultY, textCollapsedY, collapseProgress)
|
val textY = androidx.compose.ui.unit.lerp(textDefaultY, textCollapsedY, collapseProgress)
|
||||||
@@ -1210,31 +1228,60 @@ private fun CollapsingProfileHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gradient overlays when avatar is expanded
|
||||||
|
if (expandFraction > 0.01f) {
|
||||||
|
// Top gradient
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp)
|
||||||
|
.align(Alignment.TopCenter)
|
||||||
|
.graphicsLayer { alpha = expandFraction }
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Black.copy(alpha = 0.6f),
|
||||||
|
Color.Transparent
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// Bottom gradient
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp)
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.graphicsLayer { alpha = expandFraction }
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Transparent,
|
||||||
|
Color.Black.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// 🔙 BACK BUTTON - Aligned with text vertical center
|
// 🔙 BACK BUTTON - At top when expanded, centered when collapsed
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
|
val buttonsExpandedY = statusBarHeight + 8.dp
|
||||||
|
val buttonsCollapsedY = statusBarHeight + (COLLAPSED_HEADER_HEIGHT - 48.dp) / 2
|
||||||
|
val buttonsY = androidx.compose.ui.unit.lerp(buttonsExpandedY, buttonsCollapsedY, collapseProgress)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
.offset(x = 4.dp, y = textY)
|
.offset(x = 4.dp, y = buttonsY)
|
||||||
.graphicsLayer {
|
|
||||||
val centerOffsetY =
|
|
||||||
with(density) {
|
|
||||||
androidx.compose
|
|
||||||
.ui
|
|
||||||
.unit
|
|
||||||
.lerp(24.dp, 18.dp, collapseProgress)
|
|
||||||
.toPx()
|
|
||||||
}
|
|
||||||
translationY = -centerOffsetY
|
|
||||||
}
|
|
||||||
.size(48.dp),
|
.size(48.dp),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack, modifier = Modifier.size(48.dp)) {
|
IconButton(onClick = onBack, modifier = Modifier.size(48.dp)) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1243,23 +1290,12 @@ private fun CollapsingProfileHeader(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
// ⋮ MENU BUTTON / 💾 SAVE BUTTON - Aligned with text vertical center
|
// ⋮ MENU BUTTON / 💾 SAVE BUTTON - At top when expanded, centered when collapsed
|
||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
Box(
|
Box(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.align(Alignment.TopEnd)
|
Modifier.align(Alignment.TopEnd)
|
||||||
.offset(x = -4.dp, y = textY)
|
.offset(x = -4.dp, y = buttonsY),
|
||||||
.graphicsLayer {
|
|
||||||
val centerOffsetY =
|
|
||||||
with(density) {
|
|
||||||
androidx.compose
|
|
||||||
.ui
|
|
||||||
.unit
|
|
||||||
.lerp(24.dp, 18.dp, collapseProgress)
|
|
||||||
.toPx()
|
|
||||||
}
|
|
||||||
translationY = -centerOffsetY
|
|
||||||
},
|
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(visible = hasChanges, enter = fadeIn(), exit = fadeOut()) {
|
AnimatedVisibility(visible = hasChanges, enter = fadeIn(), exit = fadeOut()) {
|
||||||
@@ -1283,7 +1319,7 @@ private fun CollapsingProfileHeader(
|
|||||||
modifier = Modifier.size(48.dp)
|
modifier = Modifier.size(48.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.DotsVertical,
|
painter = TelegramIcons.More,
|
||||||
contentDescription = "Profile menu",
|
contentDescription = "Profile menu",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1312,17 +1348,7 @@ private fun CollapsingProfileHeader(
|
|||||||
// ═══════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════
|
||||||
Column(
|
Column(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.align(Alignment.TopCenter).offset(y = textY).graphicsLayer {
|
Modifier.align(Alignment.TopCenter).offset(y = textY),
|
||||||
val centerOffsetY =
|
|
||||||
with(density) {
|
|
||||||
androidx.compose
|
|
||||||
.ui
|
|
||||||
.unit
|
|
||||||
.lerp(24.dp, 18.dp, collapseProgress)
|
|
||||||
.toPx()
|
|
||||||
}
|
|
||||||
translationY = -centerOffsetY
|
|
||||||
},
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -1445,7 +1471,7 @@ fun ProfileCard(
|
|||||||
modifier = Modifier.align(Alignment.TopStart).statusBarsPadding().padding(4.dp)
|
modifier = Modifier.align(Alignment.TopStart).statusBarsPadding().padding(4.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = if (isDarkTheme) Color.White else Color.Black
|
tint = if (isDarkTheme) Color.White else Color.Black
|
||||||
)
|
)
|
||||||
@@ -1690,7 +1716,7 @@ fun TelegramCopyField(value: String, fullValue: String, label: String, isDarkThe
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TelegramSettingsItem(
|
private fun TelegramSettingsItem(
|
||||||
icon: ImageVector,
|
icon: Painter,
|
||||||
title: String,
|
title: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
isDarkTheme: Boolean,
|
isDarkTheme: Boolean,
|
||||||
@@ -1712,7 +1738,7 @@ private fun TelegramSettingsItem(
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
painter = icon,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = iconColor,
|
tint = iconColor,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1740,8 +1766,8 @@ private fun TelegramSettingsItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TelegramToggleItem(
|
fun TelegramToggleItem(
|
||||||
icon: ImageVector,
|
icon: Painter,
|
||||||
title: String,
|
title: String,
|
||||||
subtitle: String? = null,
|
subtitle: String? = null,
|
||||||
isEnabled: Boolean,
|
isEnabled: Boolean,
|
||||||
@@ -1764,7 +1790,7 @@ private fun TelegramToggleItem(
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
painter = icon,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = iconColor,
|
tint = iconColor,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1852,7 +1878,7 @@ private fun TelegramToggleItem(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun TelegramBiometricItem(isEnabled: Boolean, onToggle: () -> Unit, isDarkTheme: Boolean) {
|
private fun TelegramBiometricItem(isEnabled: Boolean, onToggle: () -> Unit, isDarkTheme: Boolean) {
|
||||||
TelegramToggleItem(
|
TelegramToggleItem(
|
||||||
icon = TablerIcons.Fingerprint,
|
icon = TelegramIcons.Fingerprint,
|
||||||
title = "Biometric Authentication",
|
title = "Biometric Authentication",
|
||||||
isEnabled = isEnabled,
|
isEnabled = isEnabled,
|
||||||
onToggle = onToggle,
|
onToggle = onToggle,
|
||||||
@@ -1872,7 +1898,7 @@ private fun TelegramLogoutItem(onClick: () -> Unit, isDarkTheme: Boolean) {
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Logout,
|
painter = TelegramIcons.Leave,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = redColor,
|
tint = redColor,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -1903,7 +1929,7 @@ private fun ProfileSectionTitle(title: String, isDarkTheme: Boolean) {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProfileNavigationItem(
|
fun ProfileNavigationItem(
|
||||||
icon: ImageVector,
|
icon: Painter,
|
||||||
iconBackground: Color,
|
iconBackground: Color,
|
||||||
title: String,
|
title: String,
|
||||||
subtitle: String,
|
subtitle: String,
|
||||||
@@ -1934,7 +1960,7 @@ fun ProfileNavigationItem(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = icon,
|
painter = icon,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
@@ -2120,6 +2146,22 @@ fun FullScreenAvatarViewer(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Bottom gradient shadow
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(120.dp)
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
.background(
|
||||||
|
Brush.verticalGradient(
|
||||||
|
colors = listOf(
|
||||||
|
Color.Transparent,
|
||||||
|
Color.Black.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
// Header: back button + name + date
|
// Header: back button + name + date
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -2130,7 +2172,7 @@ fun FullScreenAvatarViewer(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = { showContent = false }) {
|
IconButton(onClick = { showContent = false }) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Close",
|
contentDescription = "Close",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
@@ -2158,7 +2200,7 @@ fun FullScreenAvatarViewer(
|
|||||||
|
|
||||||
IconButton(onClick = { /* menu */ }) {
|
IconButton(onClick = { /* menu */ }) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.DotsVertical,
|
painter = TelegramIcons.More,
|
||||||
contentDescription = "Menu",
|
contentDescription = "Menu",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(24.dp)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
@@ -21,6 +22,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -33,6 +35,16 @@ fun ThemeScreen(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onThemeModeChange: (String) -> Unit
|
onThemeModeChange: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||||
val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
|
val surfaceColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color(0xFFF2F2F7)
|
||||||
val textColor = if (isDarkTheme) Color.White else Color.Black
|
val textColor = if (isDarkTheme) Color.White else Color.Black
|
||||||
@@ -63,7 +75,7 @@ fun ThemeScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = textColor
|
tint = textColor
|
||||||
)
|
)
|
||||||
@@ -209,7 +221,7 @@ private fun TelegramThemeOption(
|
|||||||
// Radio button
|
// Radio button
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Check,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color(0xFF007AFF),
|
tint = Color(0xFF007AFF),
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
@@ -358,7 +370,7 @@ private fun MessageBubble(
|
|||||||
if (isMe) {
|
if (isMe) {
|
||||||
// Read checkmarks (DoneAll icon like in real chat)
|
// Read checkmarks (DoneAll icon like in real chat)
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.Checks,
|
painter = TelegramIcons.Done,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = Color(0xFF4FC3F7), // Blue checkmarks for read messages
|
tint = Color(0xFF4FC3F7), // Blue checkmarks for read messages
|
||||||
modifier = Modifier.size(14.dp)
|
modifier = Modifier.size(14.dp)
|
||||||
|
|||||||
@@ -7,13 +7,16 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import compose.icons.TablerIcons
|
import compose.icons.TablerIcons
|
||||||
import compose.icons.tablericons.*
|
import compose.icons.tablericons.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.SideEffect
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -24,6 +27,16 @@ fun UpdatesScreen(
|
|||||||
isDarkTheme: Boolean,
|
isDarkTheme: Boolean,
|
||||||
onBack: () -> Unit
|
onBack: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
val view = LocalView.current
|
||||||
|
if (!view.isInEditMode) {
|
||||||
|
SideEffect {
|
||||||
|
val window = (view.context as android.app.Activity).window
|
||||||
|
val insetsController = androidx.core.view.WindowCompat.getInsetsController(window, view)
|
||||||
|
insetsController.isAppearanceLightStatusBars = !isDarkTheme
|
||||||
|
window.statusBarColor = android.graphics.Color.TRANSPARENT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val versionName = remember { BuildConfig.VERSION_NAME }
|
val versionName = remember { BuildConfig.VERSION_NAME }
|
||||||
val buildNumber = remember { BuildConfig.VERSION_CODE.toString() }
|
val buildNumber = remember { BuildConfig.VERSION_CODE.toString() }
|
||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1A1A1A) else Color(0xFFFFFFFF)
|
||||||
@@ -52,7 +65,7 @@ fun UpdatesScreen(
|
|||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = TablerIcons.ArrowLeft,
|
imageVector = TablerIcons.ChevronLeft,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
tint = if (isDarkTheme) Color.White else Color.Black
|
tint = if (isDarkTheme) Color.White else Color.Black
|
||||||
)
|
)
|
||||||
|
|||||||
BIN
app/src/main/res/drawable-hdpi/fingerprint.png
Normal file
|
After Width: | Height: | Size: 827 B |
BIN
app/src/main/res/drawable-hdpi/ic_ab_done.png
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
app/src/main/res/drawable-hdpi/ic_ab_other.png
Normal file
|
After Width: | Height: | Size: 149 B |
BIN
app/src/main/res/drawable-hdpi/ic_ab_reply.png
Normal file
|
After Width: | Height: | Size: 305 B |
BIN
app/src/main/res/drawable-hdpi/ic_arrow_drop_down.png
Normal file
|
After Width: | Height: | Size: 148 B |
BIN
app/src/main/res/drawable-hdpi/input_attach.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/drawable-hdpi/input_keyboard.png
Normal file
|
After Width: | Height: | Size: 385 B |
BIN
app/src/main/res/drawable-hdpi/input_smile.png
Normal file
|
After Width: | Height: | Size: 558 B |
BIN
app/src/main/res/drawable-hdpi/menu_unlock.png
Normal file
|
After Width: | Height: | Size: 753 B |
BIN
app/src/main/res/drawable-hdpi/msg_add.png
Normal file
|
After Width: | Height: | Size: 189 B |
BIN
app/src/main/res/drawable-hdpi/msg_addcontact.png
Normal file
|
After Width: | Height: | Size: 433 B |
BIN
app/src/main/res/drawable-hdpi/msg_addphoto.png
Normal file
|
After Width: | Height: | Size: 468 B |
BIN
app/src/main/res/drawable-hdpi/msg_arrow_back.png
Normal file
|
After Width: | Height: | Size: 257 B |
BIN
app/src/main/res/drawable-hdpi/msg_arrowright.png
Normal file
|
After Width: | Height: | Size: 193 B |
BIN
app/src/main/res/drawable-hdpi/msg_autodelete.png
Normal file
|
After Width: | Height: | Size: 461 B |
BIN
app/src/main/res/drawable-hdpi/msg_block.png
Normal file
|
After Width: | Height: | Size: 401 B |
BIN
app/src/main/res/drawable-hdpi/msg_camera.png
Normal file
|
After Width: | Height: | Size: 457 B |
BIN
app/src/main/res/drawable-hdpi/msg_close.png
Normal file
|
After Width: | Height: | Size: 268 B |
BIN
app/src/main/res/drawable-hdpi/msg_contact.png
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
app/src/main/res/drawable-hdpi/msg_customize.png
Normal file
|
After Width: | Height: | Size: 395 B |
BIN
app/src/main/res/drawable-hdpi/msg_delete.png
Normal file
|
After Width: | Height: | Size: 411 B |
BIN
app/src/main/res/drawable-hdpi/msg_edit.png
Normal file
|
After Width: | Height: | Size: 334 B |
BIN
app/src/main/res/drawable-hdpi/msg_info.png
Normal file
|
After Width: | Height: | Size: 447 B |
BIN
app/src/main/res/drawable-hdpi/msg_leave.png
Normal file
|
After Width: | Height: | Size: 340 B |
BIN
app/src/main/res/drawable-hdpi/msg_message.png
Normal file
|
After Width: | Height: | Size: 380 B |
BIN
app/src/main/res/drawable-hdpi/msg_mute.png
Normal file
|
After Width: | Height: | Size: 490 B |
BIN
app/src/main/res/drawable-hdpi/msg_notifications.png
Normal file
|
After Width: | Height: | Size: 348 B |
BIN
app/src/main/res/drawable-hdpi/msg_palette.png
Normal file
|
After Width: | Height: | Size: 460 B |
BIN
app/src/main/res/drawable-hdpi/msg_photos.png
Normal file
|
After Width: | Height: | Size: 370 B |
BIN
app/src/main/res/drawable-hdpi/msg_pin.png
Normal file
|
After Width: | Height: | Size: 391 B |
BIN
app/src/main/res/drawable-hdpi/msg_retry.png
Normal file
|
After Width: | Height: | Size: 434 B |
BIN
app/src/main/res/drawable-hdpi/msg_secret.png
Normal file
|
After Width: | Height: | Size: 344 B |
BIN
app/src/main/res/drawable-hdpi/msg_send.png
Normal file
|
After Width: | Height: | Size: 428 B |
BIN
app/src/main/res/drawable-hdpi/msg_sendfile.png
Normal file
|
After Width: | Height: | Size: 339 B |
BIN
app/src/main/res/drawable-hdpi/msg_theme.png
Normal file
|
After Width: | Height: | Size: 513 B |
BIN
app/src/main/res/drawable-hdpi/msg_unpin.png
Normal file
|
After Width: | Height: | Size: 446 B |
BIN
app/src/main/res/drawable-hdpi/msg_views.png
Normal file
|
After Width: | Height: | Size: 267 B |
BIN
app/src/main/res/drawable-hdpi/msg_warning.png
Normal file
|
After Width: | Height: | Size: 104 B |
BIN
app/src/main/res/drawable-mdpi/fingerprint.png
Normal file
|
After Width: | Height: | Size: 532 B |
BIN
app/src/main/res/drawable-mdpi/ic_ab_done.png
Normal file
|
After Width: | Height: | Size: 182 B |
BIN
app/src/main/res/drawable-mdpi/ic_ab_other.png
Normal file
|
After Width: | Height: | Size: 120 B |
BIN
app/src/main/res/drawable-mdpi/ic_ab_reply.png
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
app/src/main/res/drawable-mdpi/ic_arrow_drop_down.png
Normal file
|
After Width: | Height: | Size: 124 B |
BIN
app/src/main/res/drawable-mdpi/input_attach.png
Normal file
|
After Width: | Height: | Size: 320 B |
BIN
app/src/main/res/drawable-mdpi/input_keyboard.png
Normal file
|
After Width: | Height: | Size: 284 B |
BIN
app/src/main/res/drawable-mdpi/input_smile.png
Normal file
|
After Width: | Height: | Size: 403 B |
BIN
app/src/main/res/drawable-mdpi/menu_unlock.png
Normal file
|
After Width: | Height: | Size: 553 B |
BIN
app/src/main/res/drawable-mdpi/msg_add.png
Normal file
|
After Width: | Height: | Size: 122 B |
BIN
app/src/main/res/drawable-mdpi/msg_addcontact.png
Normal file
|
After Width: | Height: | Size: 330 B |
BIN
app/src/main/res/drawable-mdpi/msg_addphoto.png
Normal file
|
After Width: | Height: | Size: 331 B |
BIN
app/src/main/res/drawable-mdpi/msg_arrow_back.png
Normal file
|
After Width: | Height: | Size: 148 B |
BIN
app/src/main/res/drawable-mdpi/msg_arrowright.png
Normal file
|
After Width: | Height: | Size: 142 B |
BIN
app/src/main/res/drawable-mdpi/msg_autodelete.png
Normal file
|
After Width: | Height: | Size: 335 B |
BIN
app/src/main/res/drawable-mdpi/msg_block.png
Normal file
|
After Width: | Height: | Size: 275 B |
BIN
app/src/main/res/drawable-mdpi/msg_camera.png
Normal file
|
After Width: | Height: | Size: 335 B |
BIN
app/src/main/res/drawable-mdpi/msg_close.png
Normal file
|
After Width: | Height: | Size: 155 B |
BIN
app/src/main/res/drawable-mdpi/msg_contact.png
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
app/src/main/res/drawable-mdpi/msg_customize.png
Normal file
|
After Width: | Height: | Size: 280 B |
BIN
app/src/main/res/drawable-mdpi/msg_delete.png
Normal file
|
After Width: | Height: | Size: 231 B |
BIN
app/src/main/res/drawable-mdpi/msg_edit.png
Normal file
|
After Width: | Height: | Size: 239 B |
BIN
app/src/main/res/drawable-mdpi/msg_info.png
Normal file
|
After Width: | Height: | Size: 249 B |
BIN
app/src/main/res/drawable-mdpi/msg_leave.png
Normal file
|
After Width: | Height: | Size: 259 B |
BIN
app/src/main/res/drawable-mdpi/msg_message.png
Normal file
|
After Width: | Height: | Size: 251 B |
BIN
app/src/main/res/drawable-mdpi/msg_mute.png
Normal file
|
After Width: | Height: | Size: 357 B |
BIN
app/src/main/res/drawable-mdpi/msg_notifications.png
Normal file
|
After Width: | Height: | Size: 266 B |
BIN
app/src/main/res/drawable-mdpi/msg_palette.png
Normal file
|
After Width: | Height: | Size: 348 B |
BIN
app/src/main/res/drawable-mdpi/msg_photos.png
Normal file
|
After Width: | Height: | Size: 236 B |
BIN
app/src/main/res/drawable-mdpi/msg_pin.png
Normal file
|
After Width: | Height: | Size: 294 B |
BIN
app/src/main/res/drawable-mdpi/msg_retry.png
Normal file
|
After Width: | Height: | Size: 325 B |
BIN
app/src/main/res/drawable-mdpi/msg_secret.png
Normal file
|
After Width: | Height: | Size: 265 B |
BIN
app/src/main/res/drawable-mdpi/msg_send.png
Normal file
|
After Width: | Height: | Size: 317 B |
BIN
app/src/main/res/drawable-mdpi/msg_sendfile.png
Normal file
|
After Width: | Height: | Size: 242 B |
BIN
app/src/main/res/drawable-mdpi/msg_theme.png
Normal file
|
After Width: | Height: | Size: 364 B |
BIN
app/src/main/res/drawable-mdpi/msg_unpin.png
Normal file
|
After Width: | Height: | Size: 312 B |
BIN
app/src/main/res/drawable-mdpi/msg_views.png
Normal file
|
After Width: | Height: | Size: 175 B |
BIN
app/src/main/res/drawable-mdpi/msg_warning.png
Normal file
|
After Width: | Height: | Size: 73 B |
BIN
app/src/main/res/drawable-xhdpi/fingerprint.png
Normal file
|
After Width: | Height: | Size: 991 B |
BIN
app/src/main/res/drawable-xhdpi/ic_ab_done.png
Normal file
|
After Width: | Height: | Size: 216 B |