Группы: восстановление ключей по инвайту и Apple Emoji
- Добавлено восстановление локального ключа группы из инвайта при повторном нажатии, даже если на сервере статус уже JOINED. - В карточке приглашения сначала восстанавливается ключ, затем открывается группа. - Включено отображение Apple Emoji для названия/описания группы в GroupInfo и в заголовке группы в чате. - Обновлён превью-заголовок в GroupSetup на Apple Emoji рендер.
This commit is contained in:
@@ -284,6 +284,47 @@ class GroupRepository private constructor(context: Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Desktop parity fix:
|
||||||
|
* if user is already joined on server, repeated invite click should still restore local group key.
|
||||||
|
*/
|
||||||
|
suspend fun ensureLocalGroupFromInvite(
|
||||||
|
accountPublicKey: String,
|
||||||
|
accountPrivateKey: String,
|
||||||
|
inviteString: String
|
||||||
|
): GroupJoinResult {
|
||||||
|
val parsed = parseInviteString(inviteString)
|
||||||
|
?: return GroupJoinResult(
|
||||||
|
success = false,
|
||||||
|
status = GroupStatus.INVALID,
|
||||||
|
error = "Invalid invite string"
|
||||||
|
)
|
||||||
|
|
||||||
|
val existingGroupKey = getGroupKey(accountPublicKey, accountPrivateKey, parsed.groupId)
|
||||||
|
if (!existingGroupKey.isNullOrBlank()) {
|
||||||
|
return GroupJoinResult(
|
||||||
|
success = true,
|
||||||
|
status = GroupStatus.JOINED,
|
||||||
|
dialogPublicKey = toGroupDialogPublicKey(parsed.groupId),
|
||||||
|
title = parsed.title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
persistJoinedGroup(
|
||||||
|
accountPublicKey = accountPublicKey,
|
||||||
|
accountPrivateKey = accountPrivateKey,
|
||||||
|
parsedInvite = parsed,
|
||||||
|
emitSystemJoinMessage = false
|
||||||
|
)
|
||||||
|
|
||||||
|
return GroupJoinResult(
|
||||||
|
success = true,
|
||||||
|
status = GroupStatus.JOINED,
|
||||||
|
dialogPublicKey = toGroupDialogPublicKey(parsed.groupId),
|
||||||
|
title = parsed.title
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun synchronizeJoinedGroup(
|
suspend fun synchronizeJoinedGroup(
|
||||||
accountPublicKey: String,
|
accountPublicKey: String,
|
||||||
accountPrivateKey: String,
|
accountPrivateKey: String,
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ import com.rosetta.messenger.ui.chats.components.MultiImageEditorScreen
|
|||||||
import com.rosetta.messenger.ui.chats.input.*
|
import com.rosetta.messenger.ui.chats.input.*
|
||||||
import com.rosetta.messenger.ui.chats.models.*
|
import com.rosetta.messenger.ui.chats.models.*
|
||||||
import com.rosetta.messenger.ui.chats.utils.*
|
import com.rosetta.messenger.ui.chats.utils.*
|
||||||
|
import com.rosetta.messenger.ui.components.AppleEmojiText
|
||||||
import com.rosetta.messenger.ui.components.AvatarImage
|
import com.rosetta.messenger.ui.components.AvatarImage
|
||||||
import com.rosetta.messenger.ui.components.VerifiedBadge
|
import com.rosetta.messenger.ui.components.VerifiedBadge
|
||||||
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
import com.rosetta.messenger.ui.onboarding.PrimaryBlue
|
||||||
@@ -1133,21 +1134,14 @@ fun ChatDetailScreen(
|
|||||||
Alignment
|
Alignment
|
||||||
.CenterVertically
|
.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
AppleEmojiText(
|
||||||
text =
|
text = chatTitle,
|
||||||
chatTitle,
|
fontSize = 16.sp,
|
||||||
fontSize =
|
fontWeight = FontWeight.SemiBold,
|
||||||
16.sp,
|
color = Color.White,
|
||||||
fontWeight =
|
maxLines = 1,
|
||||||
FontWeight
|
overflow = android.text.TextUtils.TruncateAt.END,
|
||||||
.SemiBold,
|
enableLinks = false
|
||||||
color =
|
|
||||||
Color.White,
|
|
||||||
maxLines =
|
|
||||||
1,
|
|
||||||
overflow =
|
|
||||||
TextOverflow
|
|
||||||
.Ellipsis
|
|
||||||
)
|
)
|
||||||
if (!isSavedMessages &&
|
if (!isSavedMessages &&
|
||||||
!isGroupChat &&
|
!isGroupChat &&
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ import com.rosetta.messenger.ui.chats.components.ImageAttachment
|
|||||||
import com.rosetta.messenger.ui.chats.components.ImageSourceBounds
|
import com.rosetta.messenger.ui.chats.components.ImageSourceBounds
|
||||||
import com.rosetta.messenger.ui.chats.components.ImageViewerScreen
|
import com.rosetta.messenger.ui.chats.components.ImageViewerScreen
|
||||||
import com.rosetta.messenger.ui.chats.components.ViewableImage
|
import com.rosetta.messenger.ui.chats.components.ViewableImage
|
||||||
|
import com.rosetta.messenger.ui.components.AppleEmojiText
|
||||||
import com.rosetta.messenger.ui.components.AvatarImage
|
import com.rosetta.messenger.ui.components.AvatarImage
|
||||||
import com.rosetta.messenger.ui.components.VerifiedBadge
|
import com.rosetta.messenger.ui.components.VerifiedBadge
|
||||||
import com.rosetta.messenger.ui.icons.TelegramIcons
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
@@ -854,13 +855,14 @@ fun GroupInfoScreen(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(14.dp))
|
Spacer(modifier = Modifier.height(14.dp))
|
||||||
|
|
||||||
Text(
|
AppleEmojiText(
|
||||||
text = groupTitle,
|
text = groupTitle,
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontSize = 24.sp,
|
fontSize = 24.sp,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = android.text.TextUtils.TruncateAt.END,
|
||||||
|
enableLinks = false
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
@@ -917,12 +919,13 @@ fun GroupInfoScreen(
|
|||||||
|
|
||||||
if (groupDescription.isNotBlank()) {
|
if (groupDescription.isNotBlank()) {
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
Text(
|
AppleEmojiText(
|
||||||
text = groupDescription,
|
text = groupDescription,
|
||||||
color = Color.White.copy(alpha = 0.7f),
|
color = Color.White.copy(alpha = 0.7f),
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = android.text.TextUtils.TruncateAt.END,
|
||||||
|
enableLinks = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ import com.rosetta.messenger.network.SearchUser
|
|||||||
import com.rosetta.messenger.repository.AvatarRepository
|
import com.rosetta.messenger.repository.AvatarRepository
|
||||||
import com.rosetta.messenger.ui.components.KeyboardHeightProvider
|
import com.rosetta.messenger.ui.components.KeyboardHeightProvider
|
||||||
import com.rosetta.messenger.ui.components.OptimizedEmojiPicker
|
import com.rosetta.messenger.ui.components.OptimizedEmojiPicker
|
||||||
|
import com.rosetta.messenger.ui.components.AppleEmojiText
|
||||||
import com.rosetta.messenger.ui.components.AvatarImage
|
import com.rosetta.messenger.ui.components.AvatarImage
|
||||||
import com.rosetta.messenger.ui.icons.TelegramIcons
|
import com.rosetta.messenger.ui.icons.TelegramIcons
|
||||||
import com.rosetta.messenger.utils.AvatarFileManager
|
import com.rosetta.messenger.utils.AvatarFileManager
|
||||||
@@ -622,13 +623,14 @@ fun GroupSetupScreen(
|
|||||||
Spacer(modifier = Modifier.size(12.dp))
|
Spacer(modifier = Modifier.size(12.dp))
|
||||||
|
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
Text(
|
AppleEmojiText(
|
||||||
text = title.trim(),
|
text = title.trim(),
|
||||||
color = primaryTextColor,
|
color = primaryTextColor,
|
||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Medium,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = android.text.TextUtils.TruncateAt.END,
|
||||||
|
enableLinks = false
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(2.dp))
|
Spacer(modifier = Modifier.height(2.dp))
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -1452,7 +1452,39 @@ private fun GroupInviteInlineCard(
|
|||||||
if (parsedInvite == null) return
|
if (parsedInvite == null) return
|
||||||
|
|
||||||
if (status == GroupStatus.JOINED) {
|
if (status == GroupStatus.JOINED) {
|
||||||
openParsedGroup()
|
if (accountPublicKey.isBlank() || accountPrivateKey.isBlank()) {
|
||||||
|
openParsedGroup()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.launch {
|
||||||
|
actionLoading = true
|
||||||
|
val restoreResult =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
groupRepository.ensureLocalGroupFromInvite(
|
||||||
|
accountPublicKey = accountPublicKey,
|
||||||
|
accountPrivateKey = accountPrivateKey,
|
||||||
|
inviteString = normalizedInvite
|
||||||
|
)
|
||||||
|
}
|
||||||
|
actionLoading = false
|
||||||
|
|
||||||
|
if (restoreResult.success) {
|
||||||
|
status = GroupStatus.JOINED
|
||||||
|
groupRepository.cacheInviteInfo(
|
||||||
|
parsedInvite.groupId,
|
||||||
|
GroupStatus.JOINED,
|
||||||
|
membersCount
|
||||||
|
)
|
||||||
|
openParsedGroup()
|
||||||
|
} else {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
restoreResult.error ?: "Failed to restore group access",
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user