diff --git a/app/src/main/java/com/rosetta/messenger/data/GroupRepository.kt b/app/src/main/java/com/rosetta/messenger/data/GroupRepository.kt index d897b9a..ff1d259 100644 --- a/app/src/main/java/com/rosetta/messenger/data/GroupRepository.kt +++ b/app/src/main/java/com/rosetta/messenger/data/GroupRepository.kt @@ -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( accountPublicKey: String, accountPrivateKey: String, diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt index a54cd72..9f8a99f 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/ChatDetailScreen.kt @@ -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.models.* 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.VerifiedBadge import com.rosetta.messenger.ui.onboarding.PrimaryBlue @@ -1133,21 +1134,14 @@ fun ChatDetailScreen( Alignment .CenterVertically ) { - Text( - text = - chatTitle, - fontSize = - 16.sp, - fontWeight = - FontWeight - .SemiBold, - color = - Color.White, - maxLines = - 1, - overflow = - TextOverflow - .Ellipsis + AppleEmojiText( + text = chatTitle, + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + color = Color.White, + maxLines = 1, + overflow = android.text.TextUtils.TruncateAt.END, + enableLinks = false ) if (!isSavedMessages && !isGroupChat && diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/GroupInfoScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/GroupInfoScreen.kt index b923518..e717bbf 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/GroupInfoScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/GroupInfoScreen.kt @@ -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.ImageViewerScreen 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.VerifiedBadge import com.rosetta.messenger.ui.icons.TelegramIcons @@ -854,13 +855,14 @@ fun GroupInfoScreen( Spacer(modifier = Modifier.height(14.dp)) - Text( + AppleEmojiText( text = groupTitle, color = Color.White, fontSize = 24.sp, fontWeight = FontWeight.SemiBold, maxLines = 1, - overflow = TextOverflow.Ellipsis + overflow = android.text.TextUtils.TruncateAt.END, + enableLinks = false ) Text( @@ -917,12 +919,13 @@ fun GroupInfoScreen( if (groupDescription.isNotBlank()) { Spacer(modifier = Modifier.height(10.dp)) - Text( + AppleEmojiText( text = groupDescription, color = Color.White.copy(alpha = 0.7f), fontSize = 12.sp, maxLines = 2, - overflow = TextOverflow.Ellipsis + overflow = android.text.TextUtils.TruncateAt.END, + enableLinks = false ) } } diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/GroupSetupScreen.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/GroupSetupScreen.kt index e1b3ede..e1a4552 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/GroupSetupScreen.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/GroupSetupScreen.kt @@ -81,6 +81,7 @@ import com.rosetta.messenger.network.SearchUser import com.rosetta.messenger.repository.AvatarRepository import com.rosetta.messenger.ui.components.KeyboardHeightProvider 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.icons.TelegramIcons import com.rosetta.messenger.utils.AvatarFileManager @@ -622,13 +623,14 @@ fun GroupSetupScreen( Spacer(modifier = Modifier.size(12.dp)) Column(modifier = Modifier.weight(1f)) { - Text( + AppleEmojiText( text = title.trim(), color = primaryTextColor, fontSize = 16.sp, fontWeight = FontWeight.Medium, maxLines = 1, - overflow = TextOverflow.Ellipsis + overflow = android.text.TextUtils.TruncateAt.END, + enableLinks = false ) Spacer(modifier = Modifier.height(2.dp)) Text( diff --git a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt index bbc9aa1..f4ffb85 100644 --- a/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt +++ b/app/src/main/java/com/rosetta/messenger/ui/chats/components/ChatDetailComponents.kt @@ -1452,7 +1452,39 @@ private fun GroupInviteInlineCard( if (parsedInvite == null) return 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 }