mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
multiplatform: improve info views actions buttons design (#4622)
* multiplatform: improve info views actions buttons design * spaces * rework * fix width
This commit is contained in:
+92
-51
@@ -31,8 +31,7 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatModel.controller
|
||||
@@ -545,20 +544,22 @@ fun ChatInfoLayout(
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
Box(
|
||||
Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
SearchButton(chat, contact, close, onSearchClicked)
|
||||
Spacer(Modifier.weight(1f))
|
||||
AudioCallButton(chat, contact)
|
||||
Spacer(Modifier.weight(1f))
|
||||
VideoButton(chat, contact)
|
||||
Spacer(Modifier.weight(1f))
|
||||
MuteButton(chat, contact)
|
||||
Row(
|
||||
Modifier
|
||||
.widthIn(max = 460.dp)
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
SearchButton(modifier = Modifier.fillMaxWidth(0.25f), chat, contact, close, onSearchClicked)
|
||||
AudioCallButton(modifier = Modifier.fillMaxWidth(0.33f), chat, contact)
|
||||
VideoButton(modifier = Modifier.fillMaxWidth(0.5f), chat, contact)
|
||||
MuteButton(modifier = Modifier.fillMaxWidth(1f), chat, contact)
|
||||
}
|
||||
}
|
||||
|
||||
SectionSpacer()
|
||||
@@ -779,9 +780,16 @@ fun LocalAliasEditor(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchButton(chat: Chat, contact: Contact, close: () -> Unit, onSearchClicked: () -> Unit) {
|
||||
fun SearchButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
contact: Contact,
|
||||
close: () -> Unit,
|
||||
onSearchClicked: () -> Unit
|
||||
) {
|
||||
val disabled = !contact.ready || chat.chatItems.isEmpty()
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = painterResource(MR.images.ic_search),
|
||||
title = generalGetString(MR.strings.info_view_search_button),
|
||||
disabled = disabled,
|
||||
@@ -796,11 +804,16 @@ fun SearchButton(chat: Chat, contact: Contact, close: () -> Unit, onSearchClicke
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MuteButton(chat: Chat, contact: Contact) {
|
||||
fun MuteButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
contact: Contact
|
||||
) {
|
||||
val ntfsEnabled = remember { mutableStateOf(chat.chatInfo.ntfsEnabled) }
|
||||
val disabled = !contact.ready || !contact.active
|
||||
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = if (ntfsEnabled.value) painterResource(MR.images.ic_notifications_off) else painterResource(MR.images.ic_notifications),
|
||||
title = if (ntfsEnabled.value) stringResource(MR.strings.mute_chat) else stringResource(MR.strings.unmute_chat),
|
||||
disabled = disabled,
|
||||
@@ -812,8 +825,13 @@ fun MuteButton(chat: Chat, contact: Contact) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AudioCallButton(chat: Chat, contact: Contact) {
|
||||
fun AudioCallButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
contact: Contact
|
||||
) {
|
||||
CallButton(
|
||||
modifier = modifier,
|
||||
chat,
|
||||
contact,
|
||||
icon = painterResource(MR.images.ic_call),
|
||||
@@ -823,8 +841,13 @@ fun AudioCallButton(chat: Chat, contact: Contact) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun VideoButton(chat: Chat, contact: Contact) {
|
||||
fun VideoButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
contact: Contact
|
||||
) {
|
||||
CallButton(
|
||||
modifier = modifier,
|
||||
chat,
|
||||
contact,
|
||||
icon = painterResource(MR.images.ic_videocam),
|
||||
@@ -834,7 +857,14 @@ fun VideoButton(chat: Chat, contact: Contact) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CallButton(chat: Chat, contact: Contact, icon: Painter, title: String, mediaType: CallMediaType) {
|
||||
fun CallButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
contact: Contact,
|
||||
icon: Painter,
|
||||
title: String,
|
||||
mediaType: CallMediaType
|
||||
) {
|
||||
val canCall = contact.ready && contact.active && contact.mergedPreferences.calls.enabled.forUser && chatModel.activeCall.value == null
|
||||
val needToAllowCallsToContact = remember(chat.chatInfo) {
|
||||
chat.chatInfo is ChatInfo.Direct && with(chat.chatInfo.contact.mergedPreferences.calls) {
|
||||
@@ -845,6 +875,7 @@ fun CallButton(chat: Chat, contact: Contact, icon: Painter, title: String, media
|
||||
val allowedCallsByPrefs = remember(chat.chatInfo) { chat.chatInfo.featureEnabled(ChatFeature.Calls) }
|
||||
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = icon,
|
||||
title = title,
|
||||
disabled = chatModel.activeCall.value != null,
|
||||
@@ -907,42 +938,52 @@ private fun showCallsProhibitedAlert() {
|
||||
)
|
||||
}
|
||||
|
||||
// for ChatInfoView (it has most buttons - 4) we use Spacer(Modifier.weight(1f)) to fit,
|
||||
// for GroupChat And GroupMemberInfoViews (2 to 3 buttons) we use this as approximately equal to spacing in ChatInfoView
|
||||
val INFO_VIEW_BUTTONS_PADDING = 36.dp
|
||||
|
||||
@Composable
|
||||
fun InfoViewActionButton(icon: Painter, title: String, disabled: Boolean, disabledLook: Boolean, onClick: () -> Unit) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
enabled = !disabled
|
||||
fun InfoViewActionButton(
|
||||
modifier: Modifier,
|
||||
icon: Painter,
|
||||
title: String,
|
||||
disabled: Boolean,
|
||||
disabledLook: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Box(modifier) {
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
if (disabledLook) MaterialTheme.colors.secondaryVariant else MaterialTheme.colors.primary,
|
||||
shape = CircleShape
|
||||
)
|
||||
.padding(16.dp)
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
enabled = !disabled
|
||||
) {
|
||||
Icon(
|
||||
icon,
|
||||
contentDescription = null,
|
||||
Modifier.size(24.dp * fontSizeSqrtMultiplier),
|
||||
tint = if (disabledLook) MaterialTheme.colors.secondary else MaterialTheme.colors.onPrimary
|
||||
)
|
||||
Box(
|
||||
Modifier
|
||||
.size(56.dp)
|
||||
.background(
|
||||
if (disabledLook) MaterialTheme.colors.secondaryVariant else MaterialTheme.colors.primary,
|
||||
shape = CircleShape
|
||||
),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
icon,
|
||||
contentDescription = null,
|
||||
Modifier.size(24.dp * fontSizeSqrtMultiplier),
|
||||
tint = if (disabledLook) MaterialTheme.colors.secondary else MaterialTheme.colors.onPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
title.capitalize(Locale.current),
|
||||
Modifier.padding(top = DEFAULT_SPACE_AFTER_ICON),
|
||||
style = MaterialTheme.typography.subtitle2.copy(fontWeight = FontWeight.Normal, fontSize = 12.sp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
Text(
|
||||
title.capitalize(Locale.current),
|
||||
style = MaterialTheme.typography.subtitle2.copy(fontWeight = FontWeight.Normal),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier.padding(top = DEFAULT_SPACE_AFTER_ICON)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+39
-17
@@ -23,8 +23,7 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.unit.*
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatModel.withChats
|
||||
import chat.simplex.common.ui.theme.*
|
||||
@@ -184,10 +183,17 @@ private fun removeMemberAlert(rhId: Long?, groupInfo: GroupInfo, mem: GroupMembe
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SearchButton(chat: Chat, group: GroupInfo, close: () -> Unit, onSearchClicked: () -> Unit) {
|
||||
fun SearchButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
group: GroupInfo,
|
||||
close: () -> Unit,
|
||||
onSearchClicked: () -> Unit
|
||||
) {
|
||||
val disabled = !group.ready || chat.chatItems.isEmpty()
|
||||
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = painterResource(MR.images.ic_search),
|
||||
title = generalGetString(MR.strings.info_view_search_button),
|
||||
disabled = disabled,
|
||||
@@ -202,10 +208,15 @@ fun SearchButton(chat: Chat, group: GroupInfo, close: () -> Unit, onSearchClicke
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MuteButton(chat: Chat, groupInfo: GroupInfo) {
|
||||
fun MuteButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
groupInfo: GroupInfo
|
||||
) {
|
||||
val ntfsEnabled = remember { mutableStateOf(chat.chatInfo.ntfsEnabled) }
|
||||
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = if (ntfsEnabled.value) painterResource(MR.images.ic_notifications_off) else painterResource(MR.images.ic_notifications),
|
||||
title = if (ntfsEnabled.value) stringResource(MR.strings.mute_chat) else stringResource(MR.strings.unmute_chat),
|
||||
disabled = !groupInfo.ready,
|
||||
@@ -217,8 +228,13 @@ fun MuteButton(chat: Chat, groupInfo: GroupInfo) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddGroupMembersButton(chat: Chat, groupInfo: GroupInfo) {
|
||||
fun AddGroupMembersButton(
|
||||
modifier: Modifier,
|
||||
chat: Chat,
|
||||
groupInfo: GroupInfo
|
||||
) {
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = if (groupInfo.incognito) painterResource(MR.images.ic_add_link) else painterResource(MR.images.ic_person_add_500),
|
||||
title = stringResource(MR.strings.action_button_add_members),
|
||||
disabled = !groupInfo.ready,
|
||||
@@ -278,20 +294,26 @@ fun GroupChatInfoLayout(
|
||||
}
|
||||
SectionSpacer()
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
Box(
|
||||
Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
SearchButton(chat, groupInfo, close, onSearchClicked)
|
||||
if (groupInfo.canAddMembers) {
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
AddGroupMembersButton(chat, groupInfo)
|
||||
Row(
|
||||
Modifier
|
||||
.widthIn(max = if (groupInfo.canAddMembers) 320.dp else 230.dp)
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (groupInfo.canAddMembers) {
|
||||
SearchButton(modifier = Modifier.fillMaxWidth(0.33f), chat, groupInfo, close, onSearchClicked)
|
||||
AddGroupMembersButton(modifier = Modifier.fillMaxWidth(0.5f), chat, groupInfo)
|
||||
MuteButton(modifier = Modifier.fillMaxWidth(1f), chat, groupInfo)
|
||||
} else {
|
||||
SearchButton(modifier = Modifier.fillMaxWidth(0.5f), chat, groupInfo, close, onSearchClicked)
|
||||
MuteButton(modifier = Modifier.fillMaxWidth(1f), chat, groupInfo)
|
||||
}
|
||||
}
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
MuteButton(chat, groupInfo)
|
||||
}
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
+44
-40
@@ -327,49 +327,49 @@ fun GroupMemberInfoLayout(
|
||||
|
||||
val contactId = member.memberContactId
|
||||
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
Box(
|
||||
Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
val knownChat = if (contactId != null) knownDirectChat(contactId) else null
|
||||
if (knownChat != null) {
|
||||
val (chat, contact) = knownChat
|
||||
OpenChatButton(onClick = { openDirectChat(contact.contactId) })
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
AudioCallButton(chat, contact)
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
VideoButton(chat, contact)
|
||||
} else if (groupInfo.fullGroupPreferences.directMessages.on(groupInfo.membership)) {
|
||||
if (contactId != null) {
|
||||
OpenChatButton(onClick = { openDirectChat(contactId) }) // legacy - only relevant for direct contacts created when joining group
|
||||
} else {
|
||||
OpenChatButton(onClick = { createMemberContact() })
|
||||
Row(
|
||||
Modifier
|
||||
.widthIn(max = 320.dp)
|
||||
.padding(horizontal = DEFAULT_PADDING),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
val knownChat = if (contactId != null) knownDirectChat(contactId) else null
|
||||
if (knownChat != null) {
|
||||
val (chat, contact) = knownChat
|
||||
OpenChatButton(modifier = Modifier.fillMaxWidth(0.33f), onClick = { openDirectChat(contact.contactId) })
|
||||
AudioCallButton(modifier = Modifier.fillMaxWidth(0.5f), chat, contact)
|
||||
VideoButton(modifier = Modifier.fillMaxWidth(1f), chat, contact)
|
||||
} else if (groupInfo.fullGroupPreferences.directMessages.on(groupInfo.membership)) {
|
||||
if (contactId != null) {
|
||||
OpenChatButton(modifier = Modifier.fillMaxWidth(0.33f), onClick = { openDirectChat(contactId) }) // legacy - only relevant for direct contacts created when joining group
|
||||
} else {
|
||||
OpenChatButton(modifier = Modifier.fillMaxWidth(0.33f), onClick = { createMemberContact() })
|
||||
}
|
||||
InfoViewActionButton(modifier = Modifier.fillMaxWidth(0.5f), painterResource(MR.images.ic_call), generalGetString(MR.strings.info_view_call_button), disabled = false, disabledLook = true, onClick = {
|
||||
showSendMessageToEnableCallsAlert()
|
||||
})
|
||||
InfoViewActionButton(modifier = Modifier.fillMaxWidth(1f), painterResource(MR.images.ic_videocam), generalGetString(MR.strings.info_view_video_button), disabled = false, disabledLook = true, onClick = {
|
||||
showSendMessageToEnableCallsAlert()
|
||||
})
|
||||
} else { // no known contact chat && directMessages are off
|
||||
InfoViewActionButton(modifier = Modifier.fillMaxWidth(0.33f), painterResource(MR.images.ic_chat_bubble), generalGetString(MR.strings.info_view_message_button), disabled = false, disabledLook = true, onClick = {
|
||||
showDirectMessagesProhibitedAlert(generalGetString(MR.strings.cant_send_message_to_member_alert_title))
|
||||
})
|
||||
InfoViewActionButton(modifier = Modifier.fillMaxWidth(0.5f), painterResource(MR.images.ic_call), generalGetString(MR.strings.info_view_call_button), disabled = false, disabledLook = true, onClick = {
|
||||
showDirectMessagesProhibitedAlert(generalGetString(MR.strings.cant_call_member_alert_title))
|
||||
})
|
||||
InfoViewActionButton(modifier = Modifier.fillMaxWidth(1f), painterResource(MR.images.ic_videocam), generalGetString(MR.strings.info_view_video_button), disabled = false, disabledLook = true, onClick = {
|
||||
showDirectMessagesProhibitedAlert(generalGetString(MR.strings.cant_call_member_alert_title))
|
||||
})
|
||||
}
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
InfoViewActionButton(painterResource(MR.images.ic_call), generalGetString(MR.strings.info_view_call_button), disabled = false, disabledLook = true, onClick = {
|
||||
showSendMessageToEnableCallsAlert()
|
||||
})
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
InfoViewActionButton(painterResource(MR.images.ic_videocam), generalGetString(MR.strings.info_view_video_button), disabled = false, disabledLook = true, onClick = {
|
||||
showSendMessageToEnableCallsAlert()
|
||||
})
|
||||
} else { // no known contact chat && directMessages are off
|
||||
InfoViewActionButton(painterResource(MR.images.ic_chat_bubble), generalGetString(MR.strings.info_view_message_button), disabled = false, disabledLook = true, onClick = {
|
||||
showDirectMessagesProhibitedAlert(generalGetString(MR.strings.cant_send_message_to_member_alert_title))
|
||||
})
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
InfoViewActionButton(painterResource(MR.images.ic_call), generalGetString(MR.strings.info_view_call_button), disabled = false, disabledLook = true, onClick = {
|
||||
showDirectMessagesProhibitedAlert(generalGetString(MR.strings.cant_call_member_alert_title))
|
||||
})
|
||||
Spacer(Modifier.width(INFO_VIEW_BUTTONS_PADDING))
|
||||
InfoViewActionButton(painterResource(MR.images.ic_videocam), generalGetString(MR.strings.info_view_video_button), disabled = false, disabledLook = true, onClick = {
|
||||
showDirectMessagesProhibitedAlert(generalGetString(MR.strings.cant_call_member_alert_title))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
SectionSpacer()
|
||||
|
||||
if (member.memberActive) {
|
||||
@@ -580,8 +580,12 @@ fun RemoveMemberButton(onClick: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OpenChatButton(onClick: () -> Unit) {
|
||||
fun OpenChatButton(
|
||||
modifier: Modifier,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
InfoViewActionButton(
|
||||
modifier = modifier,
|
||||
icon = painterResource(MR.images.ic_chat_bubble),
|
||||
title = generalGetString(MR.strings.info_view_message_button),
|
||||
disabled = false,
|
||||
|
||||
Reference in New Issue
Block a user