Доработаны GroupSetup и Search: клавиатура, кнопка камеры и попап подсказок
This commit is contained in:
@@ -68,6 +68,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import coil.compose.AsyncImage
|
||||
import coil.request.ImageRequest
|
||||
import com.rosetta.messenger.R
|
||||
@@ -149,6 +150,10 @@ fun GroupSetupScreen(
|
||||
val primaryTextColor = if (isDarkTheme) Color.White else Color.Black
|
||||
val secondaryTextColor = Color(0xFF8E8E93)
|
||||
val accentColor = if (isDarkTheme) Color(0xFF5AA5FF) else Color(0xFF228BE6)
|
||||
val groupAvatarCameraButtonColor =
|
||||
if (isDarkTheme) sectionColor else Color(0xFF8CC9F6)
|
||||
val groupAvatarCameraIconColor =
|
||||
if (isDarkTheme) accentColor else Color.White
|
||||
|
||||
androidx.compose.runtime.DisposableEffect(topSurfaceColor, view) {
|
||||
val window = (view.context as? Activity)?.window
|
||||
@@ -208,12 +213,28 @@ fun GroupSetupScreen(
|
||||
}
|
||||
}
|
||||
|
||||
fun dismissInputUi() {
|
||||
if (showEmojiKeyboard || coordinator.isEmojiVisible || coordinator.isEmojiBoxVisible) {
|
||||
coordinator.closeEmoji(hideEmoji = { showEmojiKeyboard = false })
|
||||
} else {
|
||||
showEmojiKeyboard = false
|
||||
}
|
||||
focusManager.clearFocus(force = true)
|
||||
keyboardController?.hide()
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
(context as? Activity)?.window?.let { window ->
|
||||
WindowCompat.getInsetsController(window, view).hide(WindowInsetsCompat.Type.ime())
|
||||
}
|
||||
}
|
||||
|
||||
fun handleBack() {
|
||||
if (isLoading) return
|
||||
errorText = null
|
||||
if (step == GroupSetupStep.DESCRIPTION) {
|
||||
step = GroupSetupStep.DETAILS
|
||||
} else {
|
||||
dismissInputUi()
|
||||
onBack()
|
||||
}
|
||||
}
|
||||
@@ -402,7 +423,7 @@ fun GroupSetupScreen(
|
||||
Modifier
|
||||
.size(64.dp)
|
||||
.clip(CircleShape)
|
||||
.background(sectionColor)
|
||||
.background(groupAvatarCameraButtonColor)
|
||||
.clickable(enabled = !isLoading) {
|
||||
showPhotoPicker = true
|
||||
},
|
||||
@@ -423,7 +444,7 @@ fun GroupSetupScreen(
|
||||
Icon(
|
||||
painter = TelegramIcons.Camera,
|
||||
contentDescription = "Set group avatar",
|
||||
tint = accentColor,
|
||||
tint = groupAvatarCameraIconColor,
|
||||
modifier = Modifier.size(24.dp)
|
||||
)
|
||||
}
|
||||
@@ -713,6 +734,7 @@ fun GroupSetupScreen(
|
||||
avatarUriString = selectedAvatarUri
|
||||
)
|
||||
}
|
||||
dismissInputUi()
|
||||
openGroup(
|
||||
dialogPublicKey = result.dialogPublicKey,
|
||||
groupTitle = result.title.ifBlank { title.trim() }
|
||||
|
||||
@@ -32,9 +32,11 @@ import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import com.rosetta.messenger.repository.AvatarRepository
|
||||
@@ -446,9 +448,22 @@ private fun ChatsTabContent(
|
||||
val dividerColor = remember(isDarkTheme) {
|
||||
if (isDarkTheme) Color(0xFF2A2A2A) else Color(0xFFE8E8E8)
|
||||
}
|
||||
val suggestionsPrefs = remember(currentUserPublicKey) {
|
||||
context.getSharedPreferences("search_suggestions", Context.MODE_PRIVATE)
|
||||
}
|
||||
val hiddenSuggestionsKey = remember(currentUserPublicKey) {
|
||||
"hidden_frequent_${currentUserPublicKey}"
|
||||
}
|
||||
|
||||
// ─── Загрузка частых контактов из БД (top dialogs) ───
|
||||
var frequentContacts by remember { mutableStateOf<List<FrequentContact>>(emptyList()) }
|
||||
var hiddenSuggestionKeys by remember(currentUserPublicKey) { mutableStateOf<Set<String>>(emptySet()) }
|
||||
var frequentSuggestionToRemove by remember { mutableStateOf<FrequentContact?>(null) }
|
||||
|
||||
LaunchedEffect(currentUserPublicKey) {
|
||||
hiddenSuggestionKeys =
|
||||
suggestionsPrefs.getStringSet(hiddenSuggestionsKey, emptySet())?.toSet() ?: emptySet()
|
||||
}
|
||||
|
||||
LaunchedEffect(currentUserPublicKey) {
|
||||
if (currentUserPublicKey.isBlank()) return@LaunchedEffect
|
||||
@@ -478,6 +493,14 @@ private fun ChatsTabContent(
|
||||
} catch (_: Exception) { }
|
||||
}
|
||||
}
|
||||
val visibleFrequentContacts = remember(frequentContacts, hiddenSuggestionKeys) {
|
||||
frequentContacts.filterNot { hiddenSuggestionKeys.contains(it.publicKey) }
|
||||
}
|
||||
fun removeFrequentSuggestion(publicKey: String) {
|
||||
val updated = (hiddenSuggestionKeys + publicKey).toSet()
|
||||
hiddenSuggestionKeys = updated
|
||||
suggestionsPrefs.edit().putStringSet(hiddenSuggestionsKey, updated).apply()
|
||||
}
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (searchQuery.isEmpty()) {
|
||||
@@ -486,10 +509,10 @@ private fun ChatsTabContent(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
// ─── Горизонтальный ряд частых контактов (как в Telegram) ───
|
||||
if (frequentContacts.isNotEmpty()) {
|
||||
if (visibleFrequentContacts.isNotEmpty()) {
|
||||
item {
|
||||
FrequentContactsRow(
|
||||
contacts = frequentContacts,
|
||||
contacts = visibleFrequentContacts,
|
||||
avatarRepository = avatarRepository,
|
||||
isDarkTheme = isDarkTheme,
|
||||
textColor = textColor,
|
||||
@@ -504,6 +527,9 @@ private fun ChatsTabContent(
|
||||
)
|
||||
RecentSearchesManager.addUser(user)
|
||||
onUserSelect(user)
|
||||
},
|
||||
onLongPress = { contact ->
|
||||
frequentSuggestionToRemove = contact
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -653,6 +679,69 @@ private fun ChatsTabContent(
|
||||
}
|
||||
)
|
||||
}
|
||||
frequentSuggestionToRemove?.let { contact ->
|
||||
val scrimColor = if (isDarkTheme) Color.Black.copy(alpha = 0.42f) else Color.Black.copy(alpha = 0.24f)
|
||||
val popupColor = if (isDarkTheme) Color(0xFF2C2C2E) else Color.White
|
||||
val popupSecondaryText = if (isDarkTheme) Color(0xFFAEAEB2) else Color(0xFF6D6D72)
|
||||
|
||||
Box(
|
||||
modifier =
|
||||
Modifier
|
||||
.matchParentSize()
|
||||
.background(scrimColor)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) { frequentSuggestionToRemove = null }
|
||||
)
|
||||
|
||||
Surface(
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.imePadding()
|
||||
.padding(start = 20.dp, end = 20.dp, bottom = 14.dp),
|
||||
color = popupColor,
|
||||
shape = RoundedCornerShape(18.dp),
|
||||
tonalElevation = 0.dp,
|
||||
shadowElevation = 0.dp
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 18.dp, vertical = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Remove suggestion",
|
||||
color = textColor,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 17.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = "Are you sure you want to remove ${contact.name} from suggestions?",
|
||||
color = popupSecondaryText,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 22.sp
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
TextButton(onClick = { frequentSuggestionToRemove = null }) {
|
||||
Text("Cancel", color = AppPrimaryBlue, fontSize = 17.sp)
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
removeFrequentSuggestion(contact.publicKey)
|
||||
frequentSuggestionToRemove = null
|
||||
}
|
||||
) {
|
||||
Text("Remove", color = Color(0xFFFF5A5F), fontSize = 17.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,13 +758,16 @@ private data class FrequentContact(
|
||||
)
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
private fun FrequentContactsRow(
|
||||
contacts: List<FrequentContact>,
|
||||
avatarRepository: AvatarRepository?,
|
||||
isDarkTheme: Boolean,
|
||||
textColor: Color,
|
||||
onClick: (FrequentContact) -> Unit
|
||||
onClick: (FrequentContact) -> Unit,
|
||||
onLongPress: (FrequentContact) -> Unit
|
||||
) {
|
||||
val haptic = LocalHapticFeedback.current
|
||||
LazyRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -687,10 +779,15 @@ private fun FrequentContactsRow(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(72.dp)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
) { onClick(contact) }
|
||||
.combinedClickable(
|
||||
indication = null,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onClick(contact) },
|
||||
onLongClick = {
|
||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
onLongPress(contact)
|
||||
}
|
||||
)
|
||||
.padding(vertical = 4.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user