mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-23 00:02:28 +00:00
ui: allow to add/edit profile short description, length limit; allow to set welcome message for address without auto-accept (#6086)
This commit is contained in:
1 parent
7d59920399
commit
ec061bcbb9
10 files changed
+169
-93
No files matched your search
+23
-7
@@ -34,6 +34,12 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
const val MAX_BIO_LENGTH_BYTES = 160
|
||||
|
||||
fun bioFitsLimit(bio: String): Boolean {
|
||||
return chatJsonLength(bio) <= MAX_BIO_LENGTH_BYTES
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -68,18 +74,28 @@ fun CreateProfile(chatModel: ChatModel, close: () -> Unit) {
|
||||
}
|
||||
ProfileNameField(displayName, "", { it.trim() == mkValidName(it) }, focusRequester)
|
||||
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
|
||||
// Text(
|
||||
// stringResource(MR.strings.short_descr),
|
||||
// fontSize = 16.sp
|
||||
// )
|
||||
// ProfileNameField(shortDescr, "")
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
stringResource(MR.strings.short_descr),
|
||||
fontSize = 16.sp
|
||||
)
|
||||
Spacer(Modifier.height(20.dp))
|
||||
if (!bioFitsLimit(shortDescr.value)) {
|
||||
IconButton(
|
||||
onClick = { AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.bio_too_large)) },
|
||||
Modifier.size(20.dp)) {
|
||||
Icon(painterResource(MR.images.ic_info), null, tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfileNameField(shortDescr, "", isValid = { bioFitsLimit(it) })
|
||||
}
|
||||
SettingsActionItem(
|
||||
painterResource(MR.images.ic_check),
|
||||
stringResource(MR.strings.create_another_profile_button),
|
||||
disabled = !canCreateProfile(displayName.value),
|
||||
disabled = !canCreateProfile(displayName.value) || !bioFitsLimit(shortDescr.value),
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
click = {
|
||||
|
||||
+21
-12
@@ -68,7 +68,7 @@ fun GroupProfileLayout(
|
||||
shortDescr.value.trim() == (groupProfile.shortDescr ?: "") &&
|
||||
groupProfile.image == profileImage.value
|
||||
val closeWithAlert = {
|
||||
if (dataUnchanged || !canUpdateProfile(displayName.value, groupProfile)) {
|
||||
if (dataUnchanged || !canUpdateProfile(displayName.value, shortDescr.value, groupProfile)) {
|
||||
close()
|
||||
} else {
|
||||
showUnsavedChangesAlert({
|
||||
@@ -143,18 +143,27 @@ fun GroupProfileLayout(
|
||||
ProfileNameField(fullName)
|
||||
}
|
||||
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
|
||||
// Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
// Text(
|
||||
// stringResource(MR.strings.group_short_descr_field),
|
||||
// fontSize = 16.sp,
|
||||
// modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
// )
|
||||
// ProfileNameField(shortDescr)
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
stringResource(MR.strings.group_short_descr_field),
|
||||
fontSize = 16.sp,
|
||||
)
|
||||
if (!bioFitsLimit(shortDescr.value)) {
|
||||
Spacer(Modifier.size(DEFAULT_PADDING_HALF))
|
||||
IconButton(
|
||||
onClick = { AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.group_descr_too_large)) },
|
||||
Modifier.size(20.dp)
|
||||
) {
|
||||
Icon(painterResource(MR.images.ic_info), null, tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfileNameField(shortDescr, "", isValid = { bioFitsLimit(it) })
|
||||
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
val enabled = !dataUnchanged && canUpdateProfile(displayName.value, groupProfile)
|
||||
val enabled = !dataUnchanged && canUpdateProfile(displayName.value, shortDescr.value, groupProfile)
|
||||
if (enabled) {
|
||||
Text(
|
||||
stringResource(MR.strings.save_group_profile),
|
||||
@@ -189,8 +198,8 @@ fun GroupProfileLayout(
|
||||
}
|
||||
}
|
||||
|
||||
private fun canUpdateProfile(displayName: String, groupProfile: GroupProfile): Boolean =
|
||||
displayName.trim().isNotEmpty() && isValidNewProfileName(displayName, groupProfile)
|
||||
private fun canUpdateProfile(displayName: String, shortDescr: String, groupProfile: GroupProfile): Boolean =
|
||||
displayName.trim().isNotEmpty() && isValidNewProfileName(displayName, groupProfile) && bioFitsLimit(shortDescr)
|
||||
|
||||
private fun isValidNewProfileName(displayName: String, groupProfile: GroupProfile): Boolean =
|
||||
displayName == groupProfile.displayName || isValidDisplayName(displayName.trim())
|
||||
|
||||
+6
-21
@@ -396,19 +396,16 @@ private fun ModalData.UserAddressSettings(
|
||||
SectionView {
|
||||
ShareWithContactsButton(shareViaProfile, setProfileAddress)
|
||||
AutoAcceptToggle(addressSettingsState) { saveAddressSettings(addressSettingsState.value, savedAddressSettingsState) }
|
||||
if (addressSettingsState.value.autoAccept && !chatModel.addressShortLinkDataSet() && !addressSettingsState.value.businessAddress) {
|
||||
AcceptIncognitoToggle(addressSettingsState)
|
||||
}
|
||||
}
|
||||
SectionDividerSpaced()
|
||||
|
||||
// TODO v6.4.1 move auto-reply editor here
|
||||
// SectionView(stringResource(MR.strings.address_welcome_message).uppercase()) {
|
||||
// AutoReplyEditor(addressSettingsState)
|
||||
// }
|
||||
// SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
|
||||
if (addressSettingsState.value.autoAccept) {
|
||||
AutoAcceptSection(addressSettingsState = addressSettingsState)
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
SectionView(stringResource(MR.strings.address_welcome_message).uppercase()) {
|
||||
AutoReplyEditor(addressSettingsState)
|
||||
}
|
||||
SectionDividerSpaced(maxTopPadding = true, maxBottomPadding = false)
|
||||
|
||||
saveAddressSettingsButton(addressSettingsState.value == savedAddressSettingsState.value) {
|
||||
saveAddressSettings(addressSettingsState.value, savedAddressSettingsState)
|
||||
@@ -572,18 +569,6 @@ private class AddressSettingsState {
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AutoAcceptSection(addressSettingsState: MutableState<AddressSettingsState>) {
|
||||
SectionView(stringResource(MR.strings.auto_accept_contact).uppercase()) {
|
||||
if (!chatModel.addressShortLinkDataSet() && !addressSettingsState.value.businessAddress) {
|
||||
AcceptIncognitoToggle(addressSettingsState)
|
||||
}
|
||||
// TODO v6.4.1 show this message editor even with auto-accept disabled
|
||||
AutoReplyEditor(addressSettingsState)
|
||||
SectionTextFooter(stringResource(MR.strings.sent_to_your_contact_after_connection))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AcceptIncognitoToggle(addressSettingsState: MutableState<AddressSettingsState>) {
|
||||
PreferenceToggleWithIcon(
|
||||
|
||||
+21
-12
@@ -92,7 +92,7 @@ fun UserProfileLayout(
|
||||
shortDescr.value.trim() == (profile.shortDescr ?: "") &&
|
||||
profile.image == profileImage.value
|
||||
val closeWithAlert = {
|
||||
if (dataUnchanged || !canSaveProfile(displayName.value, profile)) {
|
||||
if (dataUnchanged || !canSaveProfile(displayName.value, shortDescr.value, profile)) {
|
||||
close()
|
||||
} else {
|
||||
showUnsavedChangesAlert({ saveProfile(displayName.value, fullName.value, shortDescr.value, profileImage.value) }, close)
|
||||
@@ -148,18 +148,27 @@ fun UserProfileLayout(
|
||||
ProfileNameField(fullName)
|
||||
}
|
||||
|
||||
// TODO enable in v6.4.1, limit to 160 characters
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
|
||||
// Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
// Text(
|
||||
// stringResource(MR.strings.short_descr__field),
|
||||
// fontSize = 16.sp,
|
||||
// modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
|
||||
// )
|
||||
// ProfileNameField(shortDescr)
|
||||
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
||||
Text(
|
||||
stringResource(MR.strings.short_descr__field),
|
||||
fontSize = 16.sp,
|
||||
)
|
||||
if (!bioFitsLimit(shortDescr.value)) {
|
||||
Spacer(Modifier.size(DEFAULT_PADDING_HALF))
|
||||
IconButton(
|
||||
onClick = { AlertManager.shared.showAlertMsg(title = generalGetString(MR.strings.bio_too_large)) },
|
||||
Modifier.size(20.dp)
|
||||
) {
|
||||
Icon(painterResource(MR.images.ic_info), null, tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
ProfileNameField(shortDescr)
|
||||
|
||||
Spacer(Modifier.height(DEFAULT_PADDING))
|
||||
val enabled = !dataUnchanged && canSaveProfile(displayName.value, profile)
|
||||
val enabled = !dataUnchanged && canSaveProfile(displayName.value, shortDescr.value, profile)
|
||||
val saveModifier: Modifier = Modifier.clickable(enabled) { saveProfile(displayName.value, fullName.value, shortDescr.value, profileImage.value) }
|
||||
val saveColor: Color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
Text(
|
||||
@@ -225,8 +234,8 @@ private fun isValidNewProfileName(displayName: String, profile: Profile): Boolea
|
||||
private fun showFullName(profile: Profile): Boolean =
|
||||
profile.fullName.trim().isNotEmpty() && profile.fullName.trim() != profile.displayName.trim()
|
||||
|
||||
private fun canSaveProfile(displayName: String, profile: Profile): Boolean =
|
||||
displayName.trim().isNotEmpty() && isValidNewProfileName(displayName, profile)
|
||||
private fun canSaveProfile(displayName: String, shortDescr: String, profile: Profile): Boolean =
|
||||
displayName.trim().isNotEmpty() && isValidNewProfileName(displayName, profile) && bioFitsLimit(shortDescr)
|
||||
|
||||
@Preview/*(
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
|
||||
@@ -1108,6 +1108,7 @@
|
||||
<string name="display_name__field">Profile name:</string>
|
||||
<string name="full_name__field">Full name:</string>
|
||||
<string name="short_descr__field">Bio:</string>
|
||||
<string name="bio_too_large">Bio too large</string>
|
||||
<string name="your_current_profile">Your current profile</string>
|
||||
<string name="your_profile_is_stored_on_device_and_shared_only_with_contacts_simplex_cannot_see_it">Your profile is stored on your device and shared only with your contacts. SimpleX servers cannot see your profile.</string>
|
||||
<string name="edit_image">Edit image</string>
|
||||
@@ -1916,6 +1917,7 @@
|
||||
<string name="group_display_name_field">Enter group name:</string>
|
||||
<string name="group_full_name_field">Group full name:</string>
|
||||
<string name="group_short_descr_field">Short description:</string>
|
||||
<string name="group_descr_too_large">Description too large</string>
|
||||
<string name="group_main_profile_sent">Your chat profile will be sent to group members</string>
|
||||
<string name="chat_main_profile_sent">Your chat profile will be sent to chat members</string>
|
||||
<string name="create_group_button">Create group</string>
|
||||
|
||||
Reference in new issue
Block a user