QR-коды: экран профиля в стиле Telegram (5 тем, цветной QR, логотип, аватар), сканер (CameraX + ML Kit), deep links (rosetta:// + rosetta.im), Scan QR в drawer, Share/Copy. Фикс base64 prefix в аватарках. Call: кнопка на чужом профиле, анимированный градиентный фон (iOS parity), мгновенный rejected call. Статус-бар: чёрные иконки на белом фоне + restore при уходе. Удалены dev-логи.
This commit is contained in:
@@ -671,6 +671,8 @@ sealed class Screen {
|
||||
data object CrashLogs : Screen()
|
||||
data object Biometric : Screen()
|
||||
data object Appearance : Screen()
|
||||
data object QrScanner : Screen()
|
||||
data object MyQr : Screen()
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -1028,6 +1030,8 @@ fun MainScreen(
|
||||
val isAppearanceVisible by remember {
|
||||
derivedStateOf { navStack.any { it is Screen.Appearance } }
|
||||
}
|
||||
val isQrScannerVisible by remember { derivedStateOf { navStack.any { it is Screen.QrScanner } } }
|
||||
val isMyQrVisible by remember { derivedStateOf { navStack.any { it is Screen.MyQr } } }
|
||||
var profileHasUnsavedChanges by remember(accountPublicKey) { mutableStateOf(false) }
|
||||
var showDiscardProfileChangesDialog by remember { mutableStateOf(false) }
|
||||
var discardProfileChangesFromChat by remember { mutableStateOf(false) }
|
||||
@@ -1240,7 +1244,9 @@ fun MainScreen(
|
||||
onAddAccount()
|
||||
},
|
||||
onSwitchAccount = onSwitchAccount,
|
||||
onDeleteAccountFromSidebar = onDeleteAccountFromSidebar
|
||||
onDeleteAccountFromSidebar = onDeleteAccountFromSidebar,
|
||||
onQrScanClick = { pushScreen(Screen.QrScanner) },
|
||||
onMyQrClick = { pushScreen(Screen.MyQr) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1304,6 +1310,7 @@ fun MainScreen(
|
||||
onNavigateToSafety = { pushScreen(Screen.Safety) },
|
||||
onNavigateToLogs = { pushScreen(Screen.Logs) },
|
||||
onNavigateToBiometric = { pushScreen(Screen.Biometric) },
|
||||
onNavigateToMyQr = { pushScreen(Screen.MyQr) },
|
||||
viewModel = profileViewModel,
|
||||
avatarRepository = avatarRepository,
|
||||
dialogDao = RosettaDatabase.getDatabase(context).dialogDao(),
|
||||
@@ -1542,6 +1549,7 @@ fun MainScreen(
|
||||
onNavigateToSafety = { pushScreen(Screen.Safety) },
|
||||
onNavigateToLogs = { pushScreen(Screen.Logs) },
|
||||
onNavigateToBiometric = { pushScreen(Screen.Biometric) },
|
||||
onNavigateToMyQr = { pushScreen(Screen.MyQr) },
|
||||
viewModel = profileViewModel,
|
||||
avatarRepository = avatarRepository,
|
||||
dialogDao = RosettaDatabase.getDatabase(context).dialogDao(),
|
||||
@@ -1710,6 +1718,9 @@ fun MainScreen(
|
||||
navStack = navStack.filterNot {
|
||||
it is Screen.OtherProfile || it is Screen.ChatDetail
|
||||
} + Screen.ChatDetail(chatUser)
|
||||
},
|
||||
onCall = { callableUser ->
|
||||
startCallWithPermission(callableUser)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1788,6 +1799,74 @@ fun MainScreen(
|
||||
)
|
||||
}
|
||||
|
||||
// QR Scanner
|
||||
SwipeBackContainer(
|
||||
isVisible = isQrScannerVisible,
|
||||
onBack = { navStack = navStack.filterNot { it is Screen.QrScanner } },
|
||||
isDarkTheme = isDarkTheme,
|
||||
layer = 3
|
||||
) {
|
||||
com.rosetta.messenger.ui.qr.QrScannerScreen(
|
||||
onBack = { navStack = navStack.filterNot { it is Screen.QrScanner } },
|
||||
onResult = { result ->
|
||||
navStack = navStack.filterNot { it is Screen.QrScanner }
|
||||
when (result.type) {
|
||||
com.rosetta.messenger.ui.qr.QrResultType.PROFILE -> {
|
||||
mainScreenScope.launch {
|
||||
val users = com.rosetta.messenger.network.ProtocolManager.searchUsers(result.payload, 5000)
|
||||
val user = users.firstOrNull()
|
||||
if (user != null) {
|
||||
pushScreen(Screen.OtherProfile(user))
|
||||
} else {
|
||||
val searchUser = com.rosetta.messenger.network.SearchUser(
|
||||
publicKey = result.payload,
|
||||
title = "", username = "", verified = 0, online = 0
|
||||
)
|
||||
pushScreen(Screen.ChatDetail(searchUser))
|
||||
}
|
||||
}
|
||||
}
|
||||
com.rosetta.messenger.ui.qr.QrResultType.GROUP -> {
|
||||
mainScreenScope.launch {
|
||||
val groupRepo = com.rosetta.messenger.data.GroupRepository.getInstance(context)
|
||||
val joinResult = groupRepo.joinGroup(accountPublicKey, accountPrivateKey, result.payload)
|
||||
if (joinResult.success && !joinResult.dialogPublicKey.isNullOrBlank()) {
|
||||
val groupUser = com.rosetta.messenger.network.SearchUser(
|
||||
publicKey = joinResult.dialogPublicKey,
|
||||
title = joinResult.title.ifBlank { "Group" },
|
||||
username = "", verified = 0, online = 0
|
||||
)
|
||||
pushScreen(Screen.ChatDetail(groupUser))
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// My QR Code
|
||||
SwipeBackContainer(
|
||||
isVisible = isMyQrVisible,
|
||||
onBack = { navStack = navStack.filterNot { it is Screen.MyQr } },
|
||||
isDarkTheme = isDarkTheme,
|
||||
layer = 2
|
||||
) {
|
||||
com.rosetta.messenger.ui.qr.MyQrCodeScreen(
|
||||
isDarkTheme = isDarkTheme,
|
||||
publicKey = accountPublicKey,
|
||||
displayName = accountName,
|
||||
username = accountUsername,
|
||||
avatarRepository = avatarRepository,
|
||||
onBack = { navStack = navStack.filterNot { it is Screen.MyQr } },
|
||||
onScanQr = {
|
||||
navStack = navStack.filterNot { it is Screen.MyQr }
|
||||
pushScreen(Screen.QrScanner)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (isCallScreenVisible) {
|
||||
// Блокируем любой ввод по нижележащим экранам, пока открыт полноэкранный CallOverlay.
|
||||
// Иначе тапы могут "пробивать" в чат (иконка звонка, kebab, input и т.д.).
|
||||
|
||||
Reference in New Issue
Block a user