mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-27 15:06:12 +00:00
android, desktop: knocking UI improvements and fixes (#5841)
This commit is contained in:
+1
-2
@@ -376,7 +376,7 @@ object ChatModel {
|
||||
updateContact(rhId, updatedContact)
|
||||
}
|
||||
|
||||
suspend fun updateGroup(rhId: Long?, groupInfo: GroupInfo) = updateChat(rhId, ChatInfo.Group(groupInfo, groupChatScope = null)) // TODO [knocking] review
|
||||
suspend fun updateGroup(rhId: Long?, groupInfo: GroupInfo) = updateChat(rhId, ChatInfo.Group(groupInfo, groupChatScope = null))
|
||||
|
||||
private suspend fun updateChat(rhId: Long?, cInfo: ChatInfo, addMissing: Boolean = true) {
|
||||
if (hasChat(rhId, cInfo.id)) {
|
||||
@@ -567,7 +567,6 @@ object ChatModel {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [knocking] why does this function not use `withContext(Dispatchers.Main) { ... }` ?
|
||||
fun removeChatItem(rhId: Long?, cInfo: ChatInfo, cItem: ChatItem) {
|
||||
// update chat list
|
||||
if (cInfo.groupChatScope() == null) {
|
||||
|
||||
+3
-1
@@ -191,6 +191,7 @@ class AppPreferences {
|
||||
val oneHandUICardShown = mkBoolPreference(SHARED_PREFS_ONE_HAND_UI_CARD_SHOWN, false)
|
||||
val addressCreationCardShown = mkBoolPreference(SHARED_PREFS_ADDRESS_CREATION_CARD_SHOWN, false)
|
||||
val showMuteProfileAlert = mkBoolPreference(SHARED_PREFS_SHOW_MUTE_PROFILE_ALERT, true)
|
||||
val showReportsInSupportChatAlert = mkBoolPreference(SHARED_PREFS_SHOW_REPORTS_IN_SUPPORT_CHAT_ALERT, true)
|
||||
val appLanguage = mkStrPreference(SHARED_PREFS_APP_LANGUAGE, null)
|
||||
val appUpdateChannel = mkEnumPreference(SHARED_PREFS_APP_UPDATE_CHANNEL, AppUpdatesChannel.DISABLED) { AppUpdatesChannel.entries.firstOrNull { it.name == this } }
|
||||
val appSkippedUpdate = mkStrPreference(SHARED_PREFS_APP_SKIPPED_UPDATE, "")
|
||||
@@ -273,6 +274,7 @@ class AppPreferences {
|
||||
liveMessageAlertShown to false,
|
||||
showHiddenProfilesNotice to true,
|
||||
showMuteProfileAlert to true,
|
||||
showReportsInSupportChatAlert to true,
|
||||
showDeleteConversationNotice to true,
|
||||
showDeleteContactNotice to true,
|
||||
)
|
||||
@@ -431,6 +433,7 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_ONE_HAND_UI_CARD_SHOWN = "OneHandUICardShown"
|
||||
private const val SHARED_PREFS_ADDRESS_CREATION_CARD_SHOWN = "AddressCreationCardShown"
|
||||
private const val SHARED_PREFS_SHOW_MUTE_PROFILE_ALERT = "ShowMuteProfileAlert"
|
||||
private const val SHARED_PREFS_SHOW_REPORTS_IN_SUPPORT_CHAT_ALERT = "ShowReportsInSupportChatAlert"
|
||||
private const val SHARED_PREFS_STORE_DB_PASSPHRASE = "StoreDBPassphrase"
|
||||
private const val SHARED_PREFS_INITIAL_RANDOM_DB_PASSPHRASE = "InitialRandomDBPassphrase"
|
||||
private const val SHARED_PREFS_ENCRYPTED_DB_PASSPHRASE = "EncryptedDBPassphrase"
|
||||
@@ -2711,7 +2714,6 @@ object ChatController {
|
||||
}
|
||||
is CR.MemberAcceptedByOther ->
|
||||
if (active(r.user)) {
|
||||
// TODO [knocking] update secondary context?
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.upsertGroupMember(rhId, r.groupInfo, r.member)
|
||||
}
|
||||
|
||||
+5
-6
@@ -124,7 +124,7 @@ fun ChatView(
|
||||
val supportChatInfo = ChatInfo.Group(chatInfo.groupInfo, groupChatScope = scopeInfo)
|
||||
showMemberSupportChatView(
|
||||
chatModel.chatId,
|
||||
scrollToItemId = mutableStateOf(null),
|
||||
scrollToItemId,
|
||||
supportChatInfo,
|
||||
scopeInfo
|
||||
)
|
||||
@@ -371,7 +371,7 @@ fun ChatView(
|
||||
}
|
||||
ModalManager.end.showModalCloseable(true) { close ->
|
||||
remember { derivedStateOf { chatModel.getGroupMember(member.groupMemberId) } }.value?.let { mem ->
|
||||
GroupMemberInfoView(chatRh, groupInfo, mem, stats, code, chatModel, close, close)
|
||||
GroupMemberInfoView(chatRh, groupInfo, mem, scrollToItemId, stats, code, chatModel, close, close)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,7 +806,7 @@ fun ChatLayout(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chatsCtx.contentTag == MsgContentTag.Report) { // TODO [knocking] similar bar for support chats, without archiveItems?
|
||||
if (chatsCtx.contentTag == MsgContentTag.Report) {
|
||||
Column(
|
||||
Modifier
|
||||
.layoutId(CHAT_COMPOSE_LAYOUT_ID)
|
||||
@@ -1322,8 +1322,8 @@ fun BoxScope.ChatItemsList(
|
||||
val chatInfoUpdated = rememberUpdatedState(chatInfo)
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollToItem: (Long) -> Unit = remember {
|
||||
// In group reports just set the itemId to scroll to so the main ChatView will handle scrolling
|
||||
if (chatsCtx.contentTag == MsgContentTag.Report) return@remember { scrollToItemId.value = it }
|
||||
// In secondary chat just set the itemId to scroll to so the main ChatView will handle scrolling
|
||||
if (chatsCtx.contentTag == MsgContentTag.Report || chatsCtx.secondaryContextFilter is SecondaryContextFilter.GroupChatScopeContext) return@remember { scrollToItemId.value = it }
|
||||
scrollToItem(searchValue, loadingMoreItems, animatedScrollingInProgress, highlightedItems, chatInfoUpdated, maxHeight, scope, reversedChatItems, mergedItems, listState, loadMessages)
|
||||
}
|
||||
val scrollToQuotedItemFromItem: (Long) -> Unit = remember { findQuotedItemFromItem(chatsCtx, remoteHostIdUpdated, chatInfoUpdated, scope, scrollToItem) }
|
||||
@@ -2167,7 +2167,6 @@ private fun FloatingDate(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO [knocking] same for member support chats?
|
||||
@Composable
|
||||
private fun SaveReportsStateOnDispose(chatsCtx: ChatModel.ChatsContext, listState: State<LazyListState>) {
|
||||
DisposableEffect(Unit) {
|
||||
|
||||
+13
-9
@@ -568,17 +568,21 @@ fun ComposeView(
|
||||
}
|
||||
}
|
||||
|
||||
fun showReportsInSupportChatAlert() {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.report_sent_alert_title),
|
||||
text = generalGetString(MR.strings.report_sent_alert_msg_view_in_support_chat),
|
||||
confirmText = generalGetString(MR.strings.ok),
|
||||
dismissText = generalGetString(MR.strings.dont_show_again),
|
||||
onDismiss = {
|
||||
chatModel.controller.appPrefs.showReportsInSupportChatAlert.set(false)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun sendReport(reportReason: ReportReason, chatItemId: Long): List<ChatItem>? {
|
||||
val cItems = chatModel.controller.apiReportMessage(chat.remoteHostId, chat.chatInfo.apiId, chatItemId, reportReason, msgText)
|
||||
if (cItems != null) {
|
||||
// TODO [knocking] create report chat items in support scope
|
||||
withContext(Dispatchers.Main) {
|
||||
cItems.forEach { chatItem ->
|
||||
chatsCtx.addChatItem(chat.remoteHostId, chat.chatInfo, chatItem.chatItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chatModel.controller.appPrefs.showReportsInSupportChatAlert.get()) showReportsInSupportChatAlert()
|
||||
return cItems?.map { it.chatItem }
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -101,21 +101,21 @@ fun SelectedItemsButtonsToolbar(
|
||||
)
|
||||
}
|
||||
|
||||
IconButton({ moderateItems() }, Modifier.alpha(if (canModerate.value) 1f else 0f), enabled = moderateEnabled.value && !deleteCountProhibited.value) {
|
||||
IconButton({ moderateItems() }, Modifier.alpha(if (canModerate.value) 1f else 0f), enabled = moderateEnabled.value && !deleteCountProhibited.value && chatsCtx.secondaryContextFilter == null) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_flag),
|
||||
null,
|
||||
Modifier.size(22.dp),
|
||||
tint = if (!moderateEnabled.value || deleteCountProhibited.value) MaterialTheme.colors.secondary else MaterialTheme.colors.error
|
||||
tint = if (!moderateEnabled.value || deleteCountProhibited.value || chatsCtx.secondaryContextFilter != null) MaterialTheme.colors.secondary else MaterialTheme.colors.error
|
||||
)
|
||||
}
|
||||
|
||||
IconButton({ forwardItems() }, enabled = forwardEnabled.value && !forwardCountProhibited.value) {
|
||||
IconButton({ forwardItems() }, enabled = forwardEnabled.value && !forwardCountProhibited.value && chatsCtx.secondaryContextFilter == null) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_forward),
|
||||
null,
|
||||
Modifier.size(22.dp),
|
||||
tint = if (!forwardEnabled.value || forwardCountProhibited.value) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
tint = if (!forwardEnabled.value || forwardCountProhibited.value || chatsCtx.secondaryContextFilter != null) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -78,8 +78,6 @@ fun ModalData.GroupChatInfoView(
|
||||
.filter { it.memberStatus != GroupMemberStatus.MemLeft && it.memberStatus != GroupMemberStatus.MemRemoved }
|
||||
.sortedByDescending { it.memberRole }
|
||||
|
||||
Log.e(TAG, "######### GroupChatInfoView chatModel.groupMembers length = ${chatModel.groupMembers.value.count()}")
|
||||
|
||||
GroupChatInfoLayout(
|
||||
chat,
|
||||
groupInfo,
|
||||
@@ -129,7 +127,7 @@ fun ModalData.GroupChatInfoView(
|
||||
}
|
||||
ModalManager.end.showModalCloseable(true) { closeCurrent ->
|
||||
remember { derivedStateOf { chatModel.getGroupMember(member.groupMemberId) } }.value?.let { mem ->
|
||||
GroupMemberInfoView(rhId, groupInfo, mem, stats, code, chatModel, closeCurrent) {
|
||||
GroupMemberInfoView(rhId, groupInfo, mem, scrollToItemId, stats, code, chatModel, closeCurrent) {
|
||||
closeCurrent()
|
||||
close()
|
||||
}
|
||||
@@ -148,6 +146,7 @@ fun ModalData.GroupChatInfoView(
|
||||
MemberSupportView(
|
||||
chat,
|
||||
groupInfo,
|
||||
scrollToItemId,
|
||||
close
|
||||
)
|
||||
}
|
||||
@@ -330,9 +329,11 @@ fun AddGroupMembersButton(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UserSupportChatButton(groupInfo: GroupInfo) {
|
||||
fun UserSupportChatButton(
|
||||
groupInfo: GroupInfo,
|
||||
scrollToItemId: MutableState<Long?>
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollToItemId: MutableState<Long?> = remember { mutableStateOf(null) }
|
||||
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_flag),
|
||||
@@ -463,7 +464,7 @@ fun ModalData.GroupChatInfoLayout(
|
||||
SectionView {
|
||||
if (groupInfo.membership.supportChat != null) {
|
||||
anyTopSectionRowShow = true
|
||||
UserSupportChatButton(groupInfo)
|
||||
UserSupportChatButton(groupInfo, scrollToItemId)
|
||||
}
|
||||
if (groupInfo.businessChat == null && groupInfo.membership.memberRole >= GroupMemberRole.Moderator) {
|
||||
anyTopSectionRowShow = true
|
||||
@@ -738,7 +739,7 @@ private fun GroupChatInfoHeader(cInfo: ChatInfo, groupInfo: GroupInfo) {
|
||||
@Composable
|
||||
private fun MemberSupportButton(onClick: () -> Unit) {
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_flag), // TODO [knocking] change icon
|
||||
painterResource(MR.images.ic_flag),
|
||||
stringResource(MR.strings.member_support),
|
||||
click = onClick
|
||||
)
|
||||
|
||||
+4
-1
@@ -45,6 +45,7 @@ fun GroupMemberInfoView(
|
||||
rhId: Long?,
|
||||
groupInfo: GroupInfo,
|
||||
member: GroupMember,
|
||||
scrollToItemId: MutableState<Long?>,
|
||||
connectionStats: ConnectionStats?,
|
||||
connectionCode: String?,
|
||||
chatModel: ChatModel,
|
||||
@@ -79,6 +80,7 @@ fun GroupMemberInfoView(
|
||||
rhId = rhId,
|
||||
groupInfo,
|
||||
member,
|
||||
scrollToItemId,
|
||||
connStats,
|
||||
newRole,
|
||||
developerTools,
|
||||
@@ -269,6 +271,7 @@ fun GroupMemberInfoLayout(
|
||||
rhId: Long?,
|
||||
groupInfo: GroupInfo,
|
||||
member: GroupMember,
|
||||
scrollToItemId: MutableState<Long?>,
|
||||
connStats: MutableState<ConnectionStats?>,
|
||||
newRole: MutableState<GroupMemberRole>,
|
||||
developerTools: Boolean,
|
||||
@@ -302,7 +305,6 @@ fun GroupMemberInfoLayout(
|
||||
@Composable
|
||||
fun SupportChatButton() {
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollToItemId: MutableState<Long?> = remember { mutableStateOf(null) } // TODO [knocking] scroll to report from support chat?
|
||||
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_flag),
|
||||
@@ -908,6 +910,7 @@ fun PreviewGroupMemberInfoLayout() {
|
||||
rhId = null,
|
||||
groupInfo = GroupInfo.sampleData,
|
||||
member = GroupMember.sampleData,
|
||||
scrollToItemId = remember { mutableStateOf(null) },
|
||||
connStats = remember { mutableStateOf(null) },
|
||||
newRole = remember { mutableStateOf(GroupMemberRole.Member) },
|
||||
developerTools = false,
|
||||
|
||||
+10
-2
@@ -15,7 +15,15 @@ import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Composable
|
||||
private fun GroupReportsView(reportsChatsCtx: ChatModel.ChatsContext, staleChatId: State<String?>, scrollToItemId: MutableState<Long?>) {
|
||||
private fun GroupReportsView(
|
||||
reportsChatsCtx: ChatModel.ChatsContext,
|
||||
staleChatId: State<String?>,
|
||||
scrollToItemId: MutableState<Long?>,
|
||||
close: () -> Unit
|
||||
) {
|
||||
KeyChangeEffect(chatModel.chatId.value) {
|
||||
close()
|
||||
}
|
||||
ChatView(reportsChatsCtx, staleChatId, scrollToItemId, onComposed = {})
|
||||
}
|
||||
|
||||
@@ -75,7 +83,7 @@ suspend fun showGroupReportsView(staleChatId: State<String?>, scrollToItemId: Mu
|
||||
ModalView({}, showAppBar = false) {
|
||||
val chatInfo = remember { derivedStateOf { chatModel.chats.value.firstOrNull { it.id == chatModel.chatId.value }?.chatInfo } }.value
|
||||
if (chatInfo is ChatInfo.Group && chatInfo.groupInfo.canModerate) {
|
||||
GroupReportsView(reportsChatsCtx, staleChatId, scrollToItemId)
|
||||
GroupReportsView(reportsChatsCtx, staleChatId, scrollToItemId, close)
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
close()
|
||||
|
||||
+8
-1
@@ -21,7 +21,14 @@ import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
|
||||
@Composable
|
||||
private fun MemberSupportChatView(memberSupportChatsCtx: ChatModel.ChatsContext, staleChatId: State<String?>, scrollToItemId: MutableState<Long?>) {
|
||||
private fun MemberSupportChatView(
|
||||
memberSupportChatsCtx: ChatModel.ChatsContext,
|
||||
staleChatId: State<String?>,
|
||||
scrollToItemId: MutableState<Long?>
|
||||
) {
|
||||
KeyChangeEffect(chatModel.chatId.value) {
|
||||
ModalManager.end.closeModals()
|
||||
}
|
||||
ChatView(memberSupportChatsCtx, staleChatId, scrollToItemId, onComposed = {})
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -34,15 +34,17 @@ import kotlinx.coroutines.launch
|
||||
fun ModalData.MemberSupportView(
|
||||
chat: Chat,
|
||||
groupInfo: GroupInfo,
|
||||
scrollToItemId: MutableState<Long?>,
|
||||
close: () -> Unit
|
||||
) {
|
||||
KeyChangeEffect(chat.id) {
|
||||
close()
|
||||
KeyChangeEffect(chatModel.chatId.value) {
|
||||
ModalManager.end.closeModals()
|
||||
}
|
||||
ModalView(close = close) {
|
||||
MemberSupportViewLayout(
|
||||
chat,
|
||||
groupInfo
|
||||
groupInfo,
|
||||
scrollToItemId
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -50,11 +52,11 @@ fun ModalData.MemberSupportView(
|
||||
@Composable
|
||||
private fun ModalData.MemberSupportViewLayout(
|
||||
chat: Chat,
|
||||
groupInfo: GroupInfo
|
||||
groupInfo: GroupInfo,
|
||||
scrollToItemId: MutableState<Long?>
|
||||
) {
|
||||
val oneHandUI = remember { ChatController.appPrefs.oneHandUI.state }
|
||||
val scope = rememberCoroutineScope()
|
||||
val scrollToItemId: MutableState<Long?> = remember { mutableStateOf(null) } // TODO [knocking] scroll to report from support chat?
|
||||
|
||||
val membersWithChats = remember { chatModel.groupMembers }.value
|
||||
.filter { it.supportChat != null && it.memberStatus != GroupMemberStatus.MemLeft && it.memberStatus != GroupMemberStatus.MemRemoved }
|
||||
|
||||
@@ -509,6 +509,8 @@
|
||||
<string name="report_compose_reason_header_community">Report violation: only group moderators will see it.</string>
|
||||
<string name="report_compose_reason_header_illegal">Report content: only group moderators will see it.</string>
|
||||
<string name="report_compose_reason_header_other">Report other: only group moderators will see it.</string>
|
||||
<string name="report_sent_alert_title">Report sent to moderators</string>
|
||||
<string name="report_sent_alert_msg_view_in_support_chat">You can view your reports in Support Chat.</string>
|
||||
|
||||
<!-- Images - chat.simplex.app.views.chat.item.CIImageView.kt -->
|
||||
<string name="image_descr">Image</string>
|
||||
|
||||
Reference in New Issue
Block a user