mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-29 01:09:15 +00:00
review round 3 consolidation
This commit is contained in:
+7
-1
@@ -3061,6 +3061,12 @@ object ChatController {
|
||||
r.chatItems.forEach { chatItem ->
|
||||
val cInfo = chatItem.chatInfo
|
||||
val cItem = chatItem.chatItem
|
||||
// A name arriving is the one incoming event with no other signal, so
|
||||
// the settings badge is bumped here rather than only when the names
|
||||
// screen is opened - otherwise it can never draw the user to a name.
|
||||
if (!cItem.chatDir.sent && cItem.content.msgContent is MsgContent.MCAssetTransfer) {
|
||||
chatModel.namesWaiting.value = chatModel.namesWaiting.value + 1
|
||||
}
|
||||
if (active(r.user)) {
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.addChatItem(rhId, cInfo, cItem)
|
||||
@@ -6797,7 +6803,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("nameAddress") class NameAddress(val user: User, val nameAddress: String, val nameAccount: Int, val nameMetaAddress: String): CR()
|
||||
@Serializable @SerialName("nameInfo") class NameInfo(val user: User, val nameFqdn: String, val nameOwner: String, val nameContact: List<String>, val nameChannel: List<String>, val nameExpires: Int, val nameEditCredits: Int): CR()
|
||||
@Serializable @SerialName("nameRenewed") class NameRenewed(val user: User, val nameFqdn: String, val nameExpires: Int, val nameReRegistered: Boolean): CR()
|
||||
@Serializable @SerialName("nameStatus") class NameStatus(val user: User, val nameHasWallet: Boolean, val nameKeySaved: Boolean): CR()
|
||||
@Serializable @SerialName("nameStatus") class NameStatus(val user: User, val nameHasWallet: Boolean, val nameKeySaved: Boolean, val nameAnySeed: Boolean = false): CR()
|
||||
@Serializable @SerialName("namesIncoming") class NamesIncoming(val user: User, val incomingNames: List<IncomingName>): CR()
|
||||
@Serializable @SerialName("nameAccepted") class NameAccepted(val user: User, val nameOneTimeAddr: String, val acceptedNames: List<String>): CR()
|
||||
@Serializable @SerialName("nameDeclined") class NameDeclined(val user: User, val nameOneTimeAddr: String): CR()
|
||||
|
||||
+2
-2
@@ -69,13 +69,13 @@ fun BuyNameView(rhId: Long?, close: () -> Unit) {
|
||||
val label = label.value.trim().lowercase()
|
||||
// Keyed on what is being bought, so a retry after a failed
|
||||
// registration reuses the receipt instead of charging again.
|
||||
val paid = NamePayment.purchaseFor("buy:$label:${years.value}", years.value)
|
||||
val paid = NamePayment.purchaseFor("buy:$rhId:$label:${years.value}", years.value)
|
||||
if (paid == null) return@launch // cancelled: nothing charged, nothing registered
|
||||
// Bought to be used, so it points at this profile from the moment it
|
||||
// exists rather than needing a second trip through the detail screen.
|
||||
val link = if (pointAtMe.value) myLink else null
|
||||
val reg = chatModel.controller.apiNameBuy(rhId, label, years.value, paid.token, link)
|
||||
if (reg != null) NamePayment.spent("buy:$label:${years.value}")
|
||||
if (reg != null) NamePayment.spent("buy:$rhId:$label:${years.value}")
|
||||
if (reg != null) {
|
||||
// The switch already said whether this name is for this profile, so
|
||||
// it is acted on rather than asked again. Chaining dialogs here was
|
||||
|
||||
+2
-1
@@ -52,7 +52,8 @@ fun GiveNameView(rhId: Long?, fqdn: String, close: () -> Unit) {
|
||||
}
|
||||
}
|
||||
SectionTextFooter(
|
||||
if (cannotReceive > 0) stringResource(MR.strings.names_give_some_cannot).format(cannotReceive)
|
||||
if (cannotReceive == 1) stringResource(MR.strings.names_give_one_cannot)
|
||||
else if (cannotReceive > 0) stringResource(MR.strings.names_give_some_cannot).format(cannotReceive)
|
||||
else stringResource(MR.strings.names_give_footer)
|
||||
)
|
||||
SectionBottomSpacer()
|
||||
|
||||
+15
-22
@@ -29,7 +29,7 @@ import kotlinx.coroutines.launch
|
||||
fun ImportRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
val phrase = rememberSaveable { mutableStateOf("") }
|
||||
val working = remember { mutableStateOf(false) }
|
||||
val hasWallet = remember { mutableStateOf(false) }
|
||||
val hasWallet = remember { mutableStateOf<Boolean?>(null) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -62,6 +62,17 @@ fun ImportRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(stringResource(MR.strings.names_import_title))
|
||||
|
||||
if (hasWallet.value == true) {
|
||||
// The core refuses to import over an existing key, so say so plainly
|
||||
// rather than warn about a replacement that will not happen.
|
||||
SectionView {
|
||||
SectionItemView { Text(stringResource(MR.strings.names_import_already), color = MaterialTheme.colors.secondary) }
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
return@ColumnWithScrollBar
|
||||
}
|
||||
|
||||
SectionTextFooter(stringResource(MR.strings.names_import_intro))
|
||||
|
||||
SectionView(stringResource(MR.strings.names_import_section).uppercase()) {
|
||||
@@ -77,25 +88,15 @@ fun ImportRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
}
|
||||
SectionTextFooter(
|
||||
if (phrase.value.isBlank()) stringResource(MR.strings.names_import_hint)
|
||||
else if (words.size == 1) stringResource(MR.strings.names_import_word_count_one)
|
||||
else stringResource(MR.strings.names_import_word_count).format(words.size),
|
||||
if (phrase.value.isBlank() || looksComplete) MaterialTheme.colors.secondary else WarningOrange
|
||||
)
|
||||
|
||||
if (hasWallet.value) {
|
||||
// Switching keys is not additive: names held by the current key are no
|
||||
// longer reachable from this profile afterwards.
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SectionView(stringResource(MR.strings.names_import_replace_section).uppercase()) {
|
||||
SectionItemView { Text(stringResource(MR.strings.names_import_replace_warning), color = Color.Red) }
|
||||
}
|
||||
}
|
||||
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
SectionView {
|
||||
SectionItemView(
|
||||
click = if (working.value || !looksComplete) null else {
|
||||
{ if (hasWallet.value) confirmReplace { doImport() } else doImport() }
|
||||
},
|
||||
click = if (working.value || !looksComplete) null else { { doImport() } },
|
||||
disabled = working.value || !looksComplete,
|
||||
) {
|
||||
Text(
|
||||
@@ -108,12 +109,4 @@ fun ImportRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun confirmReplace(proceed: () -> Unit) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(MR.strings.names_import_replace_title),
|
||||
text = generalGetString(MR.strings.names_import_replace_text),
|
||||
confirmText = generalGetString(MR.strings.names_import_action),
|
||||
destructive = true,
|
||||
onConfirm = proceed,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -77,8 +77,11 @@ fun IncomingNamesView(rhId: Long?, close: () -> Unit) {
|
||||
if (found != null) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.names_rescan_done_title),
|
||||
text = if (found == 0) generalGetString(MR.strings.names_rescan_none)
|
||||
else generalGetString(MR.strings.names_rescan_found).format(found)
|
||||
text = when (found) {
|
||||
0 -> generalGetString(MR.strings.names_rescan_none)
|
||||
1 -> generalGetString(MR.strings.names_rescan_found_one)
|
||||
else -> generalGetString(MR.strings.names_rescan_found).format(found)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+20
-4
@@ -29,10 +29,15 @@ import kotlinx.datetime.Instant
|
||||
@Composable
|
||||
fun NameDetailView(rhId: Long?, fqdn: String, close: () -> Unit) {
|
||||
val info = remember { mutableStateOf<CR.NameInfo?>(null) }
|
||||
val loadFailed = remember { mutableStateOf(false) }
|
||||
val busy = remember { mutableStateOf(false) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
suspend fun reload() { info.value = chatModel.controller.apiNameInfo(rhId, fqdn) }
|
||||
suspend fun reload() {
|
||||
val r = chatModel.controller.apiNameInfo(rhId, fqdn)
|
||||
info.value = r
|
||||
loadFailed.value = r == null
|
||||
}
|
||||
LaunchedEffect(Unit) { reload() }
|
||||
|
||||
val myLink = chatModel.userAddress.value?.connLinkContact?.simplexChatUri(short = true)
|
||||
@@ -40,6 +45,7 @@ fun NameDetailView(rhId: Long?, fqdn: String, close: () -> Unit) {
|
||||
NameDetailLayout(
|
||||
fqdn = fqdn,
|
||||
info = info.value,
|
||||
loadFailed = loadFailed.value,
|
||||
myLink = myLink,
|
||||
busy = busy.value,
|
||||
repoint = {
|
||||
@@ -74,9 +80,9 @@ fun NameDetailView(rhId: Long?, fqdn: String, close: () -> Unit) {
|
||||
withBGApi {
|
||||
busy.value = true
|
||||
try {
|
||||
val paid = NamePayment.purchaseFor("renew:$fqdn", 1) ?: return@withBGApi
|
||||
val paid = NamePayment.purchaseFor("renew:$rhId:$fqdn", 1) ?: return@withBGApi
|
||||
val r = chatModel.controller.apiNameRenew(rhId, fqdn, 1, paid.token)
|
||||
if (r != null) NamePayment.spent("renew:$fqdn")
|
||||
if (r != null) NamePayment.spent("renew:$rhId:$fqdn")
|
||||
if (r != null) {
|
||||
reload()
|
||||
AlertManager.shared.showAlertMsg(
|
||||
@@ -99,6 +105,7 @@ fun NameDetailView(rhId: Long?, fqdn: String, close: () -> Unit) {
|
||||
private fun NameDetailLayout(
|
||||
fqdn: String,
|
||||
info: CR.NameInfo?,
|
||||
loadFailed: Boolean,
|
||||
myLink: String?,
|
||||
busy: Boolean,
|
||||
repoint: () -> Unit,
|
||||
@@ -112,7 +119,14 @@ private fun NameDetailLayout(
|
||||
}
|
||||
|
||||
if (info == null) {
|
||||
SectionView { SectionItemView { Text(stringResource(MR.strings.names_incoming_loading), color = MaterialTheme.colors.secondary) } }
|
||||
SectionView {
|
||||
SectionItemView {
|
||||
Text(
|
||||
if (loadFailed) stringResource(MR.strings.names_list_load_failed) else stringResource(MR.strings.names_incoming_loading),
|
||||
color = if (loadFailed) WarningOrange else MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
SectionBottomSpacer()
|
||||
return@ColumnWithScrollBar
|
||||
}
|
||||
@@ -159,6 +173,7 @@ private fun NameDetailLayout(
|
||||
Text(info.nameEditCredits.toString(), color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
}
|
||||
SectionTextFooter(stringResource(MR.strings.names_detail_changes_footer))
|
||||
// The app sends no expiry notifications, so the only reminder that will
|
||||
// actually reach the user is one in their own calendar.
|
||||
SectionItemView(click = {
|
||||
@@ -238,6 +253,7 @@ private fun expiryText(expires: Long): String {
|
||||
return when {
|
||||
d < 0 -> generalGetString(MR.strings.names_detail_expired)
|
||||
d == 0L -> generalGetString(MR.strings.names_detail_expires_today)
|
||||
d == 1L -> generalGetString(MR.strings.names_detail_expires_tomorrow)
|
||||
d < 30 -> generalGetString(MR.strings.names_detail_expires_in_days).format(d)
|
||||
else -> Instant.fromEpochSeconds(expires).toString().substring(0, 10)
|
||||
}
|
||||
|
||||
+10
-1
@@ -39,6 +39,7 @@ import kotlinx.coroutines.launch
|
||||
@Composable
|
||||
fun NameRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
val phrase = remember { mutableStateOf<String?>(null) }
|
||||
val loadFailed = remember { mutableStateOf(false) }
|
||||
val saved = remember { mutableStateOf(false) }
|
||||
val revealed = remember { mutableStateOf(false) }
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -48,11 +49,14 @@ fun NameRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
if (r != null) {
|
||||
phrase.value = r.recoveryPhrase
|
||||
saved.value = r.recoveryKeySaved
|
||||
} else {
|
||||
loadFailed.value = true
|
||||
}
|
||||
}
|
||||
|
||||
NameRecoveryKeyLayout(
|
||||
phrase = phrase.value,
|
||||
loadFailed = loadFailed.value,
|
||||
saved = saved.value,
|
||||
revealed = revealed.value,
|
||||
reveal = { revealed.value = true },
|
||||
@@ -70,6 +74,7 @@ fun NameRecoveryKeyView(rhId: Long?, close: () -> Unit) {
|
||||
@Composable
|
||||
private fun NameRecoveryKeyLayout(
|
||||
phrase: String?,
|
||||
loadFailed: Boolean,
|
||||
saved: Boolean,
|
||||
revealed: Boolean,
|
||||
reveal: () -> Unit,
|
||||
@@ -88,7 +93,11 @@ private fun NameRecoveryKeyLayout(
|
||||
|
||||
SectionDividerSpaced(maxTopPadding = true)
|
||||
|
||||
if (phrase == null) {
|
||||
if (loadFailed) {
|
||||
SectionView {
|
||||
SectionItemView { Text(stringResource(MR.strings.names_list_load_failed), color = WarningOrange) }
|
||||
}
|
||||
} else if (phrase == null) {
|
||||
SectionView {
|
||||
SectionItemView { Text(stringResource(MR.strings.names_recovery_key_none), color = MaterialTheme.colors.secondary) }
|
||||
}
|
||||
|
||||
+5
-1
@@ -31,6 +31,7 @@ fun SimplexNamesView(rhId: Long?, close: () -> Unit) {
|
||||
val keySaved = remember { mutableStateOf(true) }
|
||||
val hasKey = remember { mutableStateOf(false) }
|
||||
val loadFailed = remember { mutableStateOf(false) }
|
||||
val anySeed = remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
// Status first, and nothing else until it says a wallet exists. Every other
|
||||
@@ -43,6 +44,7 @@ fun SimplexNamesView(rhId: Long?, close: () -> Unit) {
|
||||
loadFailed.value = st == null
|
||||
hasKey.value = st?.nameHasWallet ?: false
|
||||
keySaved.value = st?.nameKeySaved ?: true
|
||||
anySeed.value = st?.nameAnySeed ?: false
|
||||
if (hasKey.value) {
|
||||
names.value = chatModel.controller.apiNameList(rhId)
|
||||
incomingCount.value = chatModel.controller.apiNameIncoming(rhId)?.size ?: 0
|
||||
@@ -63,6 +65,7 @@ fun SimplexNamesView(rhId: Long?, close: () -> Unit) {
|
||||
keySaved = keySaved.value,
|
||||
hasKey = hasKey.value,
|
||||
loadFailed = loadFailed.value,
|
||||
hasOtherSeed = anySeed.value,
|
||||
rhId = rhId,
|
||||
)
|
||||
}
|
||||
@@ -75,6 +78,7 @@ private fun SimplexNamesLayout(
|
||||
keySaved: Boolean,
|
||||
hasKey: Boolean,
|
||||
loadFailed: Boolean,
|
||||
hasOtherSeed: Boolean,
|
||||
rhId: Long?,
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
@@ -140,7 +144,7 @@ private fun SimplexNamesLayout(
|
||||
if (!hasKey) SettingsActionItem(
|
||||
painterResource(MR.images.ic_add),
|
||||
stringResource(MR.strings.names_setup_title),
|
||||
click = { ModalManager.start.showModalCloseable { c -> WalletSetupView(rhId, hasOtherSeed = false, onDone = c) } },
|
||||
click = { ModalManager.start.showModalCloseable { c -> WalletSetupView(rhId, hasOtherSeed = hasOtherSeed, onDone = c) } },
|
||||
textColor = MaterialTheme.colors.primary,
|
||||
iconColor = MaterialTheme.colors.primary,
|
||||
)
|
||||
|
||||
@@ -3217,6 +3217,7 @@
|
||||
<string name="names_rescan_done_title">Check complete</string>
|
||||
<string name="names_rescan_none">No new names found.</string>
|
||||
<string name="names_rescan_found">Found %d names sent to you — see the list above.</string>
|
||||
<string name="names_rescan_found_one">Found a name sent to you — see the list above.</string>
|
||||
<string name="names_title">SimpleX names</string>
|
||||
<string name="names_your_names">Your names</string>
|
||||
<string name="names_none_yet">You do not have a name yet</string>
|
||||
@@ -3248,7 +3249,7 @@
|
||||
<string name="names_buy_taken">That name is already taken.</string>
|
||||
<string name="names_buy_action">Buy this name — %s</string>
|
||||
<string name="names_buy_working">Registering…</string>
|
||||
<string name="names_buy_failed">Could not get the name</string>
|
||||
<string name="names_buy_failed">Could not buy the name</string>
|
||||
<string name="names_bought_title">The name is yours</string>
|
||||
<string name="names_bought_text">%s now points at this profile.</string>
|
||||
<string name="names_bought_save_key">Save recovery key</string>
|
||||
@@ -3286,6 +3287,7 @@
|
||||
<string name="names_give_nobody">None of your contacts can receive a name yet.</string>
|
||||
<string name="names_give_footer">Only contacts who can receive names are listed.</string>
|
||||
<string name="names_give_some_cannot">%d of your contacts cannot receive names yet — they need a newer app version, or to turn receiving on.</string>
|
||||
<string name="names_give_one_cannot">One of your contacts cannot receive names yet — they need a newer app version, or to turn receiving on.</string>
|
||||
<string name="names_give_confirm_title">Give the name away?</string>
|
||||
<string name="names_give_confirm_text">%1$s will belong to %2$s. Only they will be able to change or move it after this.</string>
|
||||
<string name="names_give_action">Give it away</string>
|
||||
@@ -3311,24 +3313,22 @@
|
||||
<string name="names_buy_no_address">You do not have a SimpleX address yet, so there is nothing for the name to point at. Create one first, or buy the name to give away.</string>
|
||||
<string name="names_transfer_sent">You sent the SimpleX name %s</string>
|
||||
<string name="names_transfer_received">You were sent the SimpleX name %s — open SimpleX names to accept it</string>
|
||||
<string name="names_transfer_unknown">You were given a SimpleX name. Update SimpleX to accept it.</string>
|
||||
<string name="names_transfer_unknown">You were sent a SimpleX name. Update SimpleX to accept it.</string>
|
||||
<string name="names_import_title">Restore names from a recovery key</string>
|
||||
<string name="names_import_intro">If you have a recovery key from another device, enter it here to get your names back. Nothing is bought and no one is contacted.</string>
|
||||
<string name="names_import_section">Recovery key</string>
|
||||
<string name="names_import_placeholder">your recovery words, separated by spaces</string>
|
||||
<string name="names_import_hint">Enter the words in the order they were shown to you.</string>
|
||||
<string name="names_import_word_count">%d words entered — a recovery key has 12, 15, 18, 21 or 24.</string>
|
||||
<string name="names_import_word_count_one">1 word entered — a recovery key has 12, 15, 18, 21 or 24.</string>
|
||||
<string name="names_import_action">Restore</string>
|
||||
<string name="names_import_working">Restoring…</string>
|
||||
<string name="names_import_failed">That recovery key was not accepted</string>
|
||||
<string name="names_import_done_title">Restored</string>
|
||||
<string name="names_import_done_none">No names were found for that recovery key yet.</string>
|
||||
<string name="names_import_done_found">Found %d names sent to you.</string>
|
||||
<string name="names_import_replace_section">This will replace your current key</string>
|
||||
<string name="names_import_replace_warning">This profile already has a recovery key. Restoring a different one means names held by the current key can no longer be reached from this profile.</string>
|
||||
<string name="names_import_replace_title">Replace your recovery key?</string>
|
||||
<string name="names_import_replace_text">Names held by your current key will no longer be reachable from this profile. Make sure you have saved it first.</string>
|
||||
<string name="names_import_done_none">Recovery key added. Open Your names to see what it holds.</string>
|
||||
<string name="names_import_done_found">Recovery key added, and %d names were sent to you. Check Your names and names sent to you.</string>
|
||||
<string name="names_detail_expires_in_days">In %d days</string>
|
||||
<string name="names_detail_expires_tomorrow">Tomorrow</string>
|
||||
<string name="names_detail_changes_footer">Pointing this name somewhere new uses one change. Extending the name adds 10 more.</string>
|
||||
<string name="names_renew_action">Extend this name</string>
|
||||
<string name="names_renew_title">Extend this name?</string>
|
||||
@@ -3354,4 +3354,5 @@
|
||||
<string name="names_setup_footer_shared">Using the key you already have means one set of words to write down, and it covers every profile. A separate key keeps this profile\'s names unconnected to your others, but is a second thing to keep safe.</string>
|
||||
<string name="names_setup_footer_first">You will be shown the key afterwards. Write it down — it is the only way to get your names back if you lose this device.</string>
|
||||
<string name="names_setup_failed">Could not set up names for this profile</string>
|
||||
<string name="names_import_already">This profile already has a recovery key, so you cannot import a different one here. To use another key, set up a new profile and import it there.</string>
|
||||
</resources>
|
||||
@@ -964,7 +964,7 @@ data ChatResponse
|
||||
| CRNameAddress {user :: User, nameAddress :: Text, nameAccount :: Int, nameMetaAddress :: Text}
|
||||
| -- | Read-only: never creates a wallet. Screens use this to decide what to
|
||||
-- offer, so that opening one cannot create keys or notify contacts.
|
||||
CRNameStatus {user :: User, nameHasWallet :: Bool, nameKeySaved :: Bool}
|
||||
CRNameStatus {user :: User, nameHasWallet :: Bool, nameKeySaved :: Bool, nameAnySeed :: Bool}
|
||||
| CRNameRecoveryKey {user :: User, recoveryPhrase :: Text, recoveryKeySaved :: Bool}
|
||||
| CRNameQuoted {user :: User, nameLabel :: Text, nameAvailable :: Bool, namePriceCents :: Int}
|
||||
| CRNameRegistered {user :: User, nameFqdn :: Text, nameTxHash :: Text}
|
||||
|
||||
@@ -2413,13 +2413,14 @@ processChatCommand cxt nm = \case
|
||||
r <- withStore' $ \db -> WS.bindNewAccountOnSeed db user w
|
||||
-- Contacts need the new address before they can send anything to it.
|
||||
void $ publishMetaAddress user
|
||||
pure $ CRNameStatus user True (W.wsBackedUp w)
|
||||
pure $ CRNameStatus user True (W.wsBackedUp w) True
|
||||
APINameStatus userId -> withUserId userId $ \user -> do
|
||||
ref <- withStore' $ \db -> WS.getAccountRef db user
|
||||
saved <- case ref of
|
||||
Nothing -> pure False
|
||||
Just r -> maybe False W.wsBackedUp <$> withStore' (\db -> WS.getWalletSeed db (W.arSeedId r))
|
||||
pure $ CRNameStatus user (isJust ref) saved
|
||||
anySeed <- not . null <$> withStore' WS.getWalletSeeds
|
||||
pure $ CRNameStatus user (isJust ref) saved anySeed
|
||||
APINameAddress userId -> withUserId userId $ \user -> do
|
||||
-- Asking to see your address is an explicit act, so publishing here is
|
||||
-- fine - it is how someone can receive a name before buying one. What must
|
||||
@@ -2594,10 +2595,11 @@ processChatCommand cxt nm = \case
|
||||
-- twice.
|
||||
forM_ ct_ $ \ct -> do
|
||||
let mc = MCAssetTransfer {text = "You were given the SimpleX name " <> fqdn, transfer = AssetTransfer {kind = "simplexName", asset = fqdn, ephemeralPubKey = Just ephHex}}
|
||||
-- Protocol message only. Creating a local chat item here made this
|
||||
-- command's own response be emitted twice; the sender's bubble is the
|
||||
-- client's business, not the core's.
|
||||
void $ sendDirectContactMessage user ct $ XMsgNew $ mcSimple mc
|
||||
-- Best-effort: the transfer already landed on chain above, so a failed
|
||||
-- notification must not fail the command and report the gift as failed
|
||||
-- for a name that has already moved. Protocol message only; the sender's
|
||||
-- bubble is the client's business.
|
||||
(void (sendDirectContactMessage user ct $ XMsgNew $ mcSimple mc)) `catchAllErrors` \_ -> pure ()
|
||||
-- The profile must stop advertising a name it no longer owns, or contacts
|
||||
-- keep seeing it and the user's own list reports it as not managed here.
|
||||
let User {profile = LocalProfile {contactDomain}} = user
|
||||
|
||||
@@ -159,7 +159,7 @@ chatResponseToView hu cfg@ChatConfig {logLevel, showReactions, showFullLinks, te
|
||||
CRNameGifted u fqdn tx _eph -> ttyUser u ["gift " <> plain fqdn <> " done", "tx " <> plain tx]
|
||||
CRNameRenewed u fqdn expires reReg ->
|
||||
ttyUser u [(if reReg then "registered again: " else "renewed: ") <> plain fqdn, "expires " <> sShow expires]
|
||||
CRNameStatus u hasWallet keySaved ->
|
||||
CRNameStatus u hasWallet keySaved _anySeed ->
|
||||
ttyUser u [if hasWallet then (if keySaved then "wallet ready, recovery key saved" else "wallet ready, recovery key NOT saved") else "no wallet yet - people cannot send you names"]
|
||||
CRNamesIncoming u ns
|
||||
| null ns -> ttyUser u ["no names have been sent to you"]
|
||||
|
||||
Reference in New Issue
Block a user