Skip to content

Commit bb5fc1d

Browse files
authored
SES-4753 - New message sheet string changes (#1652)
* New message description icon change * Ons lookup failed error * unregistered ONS error string * Modal when clicking help * Invalid account id check * Updated url dialog commands
1 parent 7cbfb56 commit bb5fc1d

File tree

4 files changed

+84
-16
lines changed

4 files changed

+84
-16
lines changed

app/src/main/java/org/session/libsignal/utilities/Validation.kt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,24 @@ object PublicKeyValidation {
44
private val HEX_CHARACTERS = "0123456789ABCDEFabcdef".toSet()
55
private val INVALID_PREFIXES = setOf(IdPrefix.GROUP, IdPrefix.BLINDED, IdPrefix.BLINDEDV2)
66

7-
fun isValid(candidate: String, isPrefixRequired: Boolean = true): Boolean = hasValidLength(candidate) && isValidHexEncoding(candidate) && (!isPrefixRequired || IdPrefix.fromValue(candidate) != null)
7+
fun isValid(candidate: String, isPrefixRequired: Boolean = true): Boolean {
8+
if (!hasValidLength(candidate)) return false
9+
10+
val prefix = IdPrefix.fromValue(candidate)
11+
12+
// Handle invalid Account ID conditions
13+
// Case 1: Standard prefix "05" but not valid hex
14+
if (prefix == IdPrefix.STANDARD && !isValidHexEncoding(candidate)) return false
15+
16+
// Case 2: Blinded or Group IDs should never be accepted as valid Account IDs
17+
if (prefix in INVALID_PREFIXES) return false
18+
19+
// Standard validity rules
20+
return isValidHexEncoding(candidate) &&
21+
(!isPrefixRequired || prefix != null)
22+
}
23+
824
fun hasValidPrefix(candidate: String) = IdPrefix.fromValue(candidate) !in INVALID_PREFIXES
9-
private fun hasValidLength(candidate: String) = candidate.length == 66
25+
fun hasValidLength(candidate: String) = candidate.length == 66
1026
private fun isValidHexEncoding(candidate: String) = HEX_CHARACTERS.containsAll(candidate.toSet())
1127
}

app/src/main/java/org/thoughtcrime/securesms/home/startconversation/StartConversationSheet.kt

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import androidx.compose.runtime.Composable
1616
import androidx.compose.runtime.LaunchedEffect
1717
import androidx.compose.runtime.collectAsState
1818
import androidx.compose.runtime.getValue
19+
import androidx.compose.runtime.mutableStateOf
1920
import androidx.compose.runtime.remember
2021
import androidx.compose.runtime.rememberCoroutineScope
22+
import androidx.compose.runtime.setValue
2123
import androidx.compose.ui.Alignment
2224
import androidx.compose.ui.Modifier
2325
import androidx.compose.ui.platform.LocalContext
@@ -39,6 +41,7 @@ import org.thoughtcrime.securesms.home.startconversation.newmessage.State
3941
import org.thoughtcrime.securesms.openUrl
4042
import org.thoughtcrime.securesms.ui.NavigationAction
4143
import org.thoughtcrime.securesms.ui.ObserveAsEvents
44+
import org.thoughtcrime.securesms.ui.OpenURLAlertDialog
4245
import org.thoughtcrime.securesms.ui.UINavigator
4346
import org.thoughtcrime.securesms.ui.components.BaseBottomSheet
4447
import org.thoughtcrime.securesms.ui.horizontalSlideComposable
@@ -152,13 +155,17 @@ fun StartConversationNavHost(
152155
val viewModel = hiltViewModel<NewMessageViewModel>()
153156
val uiState by viewModel.state.collectAsState(State())
154157

158+
val helpUrl = "https://getsession.org/account-ids"
159+
155160
LaunchedEffect(Unit) {
156161
scope.launch {
157162
viewModel.success.collect {
158-
context.startActivity(ConversationActivityV2.createIntent(
159-
context,
160-
address = it.address
161-
))
163+
context.startActivity(
164+
ConversationActivityV2.createIntent(
165+
context,
166+
address = it.address
167+
)
168+
)
162169

163170
onClose()
164171
}
@@ -169,10 +176,16 @@ fun StartConversationNavHost(
169176
uiState,
170177
viewModel.qrErrors,
171178
viewModel,
172-
onBack = { scope.launch { navigator.navigateUp() }},
179+
onBack = { scope.launch { navigator.navigateUp() } },
173180
onClose = onClose,
174-
onHelp = { activity?.openUrl("https://sessionapp.zendesk.com/hc/en-us/articles/4439132747033-How-do-Account-ID-usernames-work") }
181+
onHelp = { viewModel.onCommand(NewMessageViewModel.Commands.ShowUrlDialog) }
175182
)
183+
if (uiState.showUrlDialog) {
184+
OpenURLAlertDialog(
185+
url = helpUrl,
186+
onDismissRequest = { viewModel.onCommand(NewMessageViewModel.Commands.DismissUrlDialog) }
187+
)
188+
}
176189
}
177190

178191
// Create Group

app/src/main/java/org/thoughtcrime/securesms/home/startconversation/newmessage/NewMessage.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ private fun EnterAccountId(
124124
.fillMaxWidth(),
125125
style = LocalType.current.small,
126126
color = LocalColors.current.textSecondary,
127-
iconRes = R.drawable.ic_circle_help,
127+
iconRes = R.drawable.ic_square_arrow_up_right,
128128
onClick = onHelp
129129
)
130130
}

app/src/main/java/org/thoughtcrime/securesms/home/startconversation/newmessage/NewMessageViewModel.kt

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.app.Application
44
import androidx.lifecycle.AndroidViewModel
55
import androidx.lifecycle.ViewModel
66
import androidx.lifecycle.viewModelScope
7+
import com.squareup.phrase.Phrase
78
import dagger.hilt.android.lifecycle.HiltViewModel
89
import kotlinx.coroutines.Job
910
import kotlinx.coroutines.channels.BufferOverflow
@@ -19,9 +20,11 @@ import org.session.libsession.snode.SnodeAPI
1920
import org.session.libsession.utilities.Address
2021
import org.session.libsession.utilities.Address.Companion.toAddress
2122
import org.session.libsession.utilities.ConfigFactoryProtocol
23+
import org.session.libsession.utilities.StringSubstitutionConstants.APP_NAME_KEY
2224
import org.session.libsession.utilities.upsertContact
2325
import org.session.libsignal.utilities.Log
2426
import org.session.libsignal.utilities.PublicKeyValidation
27+
import org.thoughtcrime.securesms.preferences.SettingsViewModel
2528
import org.thoughtcrime.securesms.ui.GetString
2629
import java.net.IDN
2730
import javax.inject.Inject
@@ -69,10 +72,20 @@ class NewMessageViewModel @Inject constructor(
6972
}
7073
}
7174

72-
if (PublicKeyValidation.isValid(idOrONS, isPrefixRequired = false)) {
73-
onUnvalidatedPublicKey(publicKey = idOrONS)
75+
if (PublicKeyValidation.hasValidLength(idOrONS)) {
76+
if (PublicKeyValidation.isValid(idOrONS, isPrefixRequired = false)) {
77+
onUnvalidatedPublicKey(idOrONS)
78+
} else {
79+
_state.update {
80+
it.copy(
81+
isTextErrorColor = true,
82+
error = GetString(R.string.accountIdErrorInvalid),
83+
loading = false
84+
)
85+
}
86+
}
7487
} else {
75-
resolveONS(ons = idOrONS)
88+
resolveONS(idOrONS)
7689
}
7790
}
7891

@@ -122,7 +135,6 @@ class NewMessageViewModel @Inject constructor(
122135
if (address is Address.Standard) {
123136
viewModelScope.launch { _success.emit(Success(address)) }
124137
}
125-
126138
}
127139

128140
private fun onUnvalidatedPublicKey(publicKey: String) {
@@ -134,18 +146,45 @@ class NewMessageViewModel @Inject constructor(
134146
}
135147

136148
private fun Exception.toMessage() = when (this) {
137-
is SnodeAPI.Error.Generic -> application.getString(R.string.onsErrorNotRecognized)
138-
else -> application.getString(R.string.onsErrorUnableToSearch)
149+
is SnodeAPI.Error.Generic -> application.getString(R.string.errorUnregisteredOns)
150+
else -> Phrase.from(application, R.string.errorNoLookupOns)
151+
.put(APP_NAME_KEY, application.getString(R.string.app_name))
152+
.format().toString()
153+
}
154+
155+
fun onCommand(commands: Commands) {
156+
when (commands) {
157+
is Commands.ShowUrlDialog -> {
158+
_state.update { it.copy(showUrlDialog = true) }
159+
}
160+
161+
is Commands.DismissUrlDialog -> {
162+
_state.update {
163+
it.copy(
164+
showUrlDialog = false
165+
)
166+
}
167+
}
168+
}
169+
}
170+
171+
sealed interface Commands {
172+
data object ShowUrlDialog : Commands
173+
data object DismissUrlDialog : Commands
139174
}
140175
}
141176

142177
data class State(
143178
val newMessageIdOrOns: String = "",
144179
val isTextErrorColor: Boolean = false,
145180
val error: GetString? = null,
146-
val loading: Boolean = false
181+
val loading: Boolean = false,
182+
val showUrlDialog : Boolean = false
147183
) {
148184
val isNextButtonEnabled: Boolean get() = newMessageIdOrOns.isNotBlank()
149185
}
150186

187+
188+
189+
151190
data class Success(val address: Address.Standard)

0 commit comments

Comments
 (0)