mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
fix(concord): tell the user when a join or creation could not be saved
When the Community List refused a membership (not loaded yet, or every held fragment full with others missing), the invite flow still reported Joined and creation still returned the new community. It looked joined until the next restart, then was gone. The join now fails with a retryable NotSaved and announces nothing, and creation returns null so the create screen shows its failure message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
cd5c92bd1b
commit
524d0f7031
+27
-22
@@ -146,8 +146,11 @@ class AccountConcordActions(
|
||||
inviteCreator: HexKey? = null,
|
||||
inviteLabel: String? = null,
|
||||
fetchedWraps: List<Event> = emptyList(),
|
||||
) {
|
||||
if (!persistConcordEntry(entry)) return
|
||||
): Boolean {
|
||||
// False when the List could not take the membership (not loaded, or every held fragment is
|
||||
// full while others are missing, CORD-02 §8). Callers must say so: the community would
|
||||
// otherwise look joined now and be gone after a restart.
|
||||
if (!persistConcordEntry(entry)) return false
|
||||
// The session is built asynchronously from the Community List flow. Every wrap that reaches
|
||||
// the cache before it exists is kept as an unclaimed note, and the live subscription's copy
|
||||
// of the same wrap is then deduplicated away, so the community showed "No channels yet"
|
||||
@@ -155,6 +158,7 @@ class AccountConcordActions(
|
||||
awaitConcordSession(entry.id)
|
||||
fetchedWraps.forEach { account.concordSessions.ingest(it) }
|
||||
announceConcordGuestbookJoin(entry, inviteCreator, inviteLabel)
|
||||
return true
|
||||
}
|
||||
|
||||
/** The community's current name: its folded metadata, else the name it was joined under. */
|
||||
@@ -264,24 +268,25 @@ class AccountConcordActions(
|
||||
return null
|
||||
}
|
||||
|
||||
joinConcordCommunity(
|
||||
ConcordCommunityListEntry(
|
||||
id = community.communityIdHex,
|
||||
owner = community.ownerPubKey,
|
||||
ownerSalt = community.ownerSalt.toHexKey(),
|
||||
root = community.communityRoot.toHexKey(),
|
||||
rootEpoch = community.rootEpoch,
|
||||
// The creator is the founding staff member (CORD-02 §2): it keeps the write
|
||||
// secret and publishes only the derived pubkey to everyone else.
|
||||
controlPk = community.controlPkHex,
|
||||
controlRoot = community.controlRoot.toHexKey(),
|
||||
relays = relayUrls,
|
||||
name = name,
|
||||
addedAt = TimeUtils.nowMillis(),
|
||||
),
|
||||
fetchedWraps = community.genesisWraps,
|
||||
)
|
||||
return community.communityIdHex
|
||||
val saved =
|
||||
joinConcordCommunity(
|
||||
ConcordCommunityListEntry(
|
||||
id = community.communityIdHex,
|
||||
owner = community.ownerPubKey,
|
||||
ownerSalt = community.ownerSalt.toHexKey(),
|
||||
root = community.communityRoot.toHexKey(),
|
||||
rootEpoch = community.rootEpoch,
|
||||
// The creator is the founding staff member (CORD-02 §2): it keeps the write
|
||||
// secret and publishes only the derived pubkey to everyone else.
|
||||
controlPk = community.controlPkHex,
|
||||
controlRoot = community.controlRoot.toHexKey(),
|
||||
relays = relayUrls,
|
||||
name = name,
|
||||
addedAt = TimeUtils.nowMillis(),
|
||||
),
|
||||
fetchedWraps = community.genesisWraps,
|
||||
)
|
||||
return community.communityIdHex.takeIf { saved }
|
||||
}
|
||||
|
||||
// ---- CORD-05 Invite List (kind 13303) -------------------------------------
|
||||
@@ -689,7 +694,7 @@ class AccountConcordActions(
|
||||
if (rejoined != null) {
|
||||
if (!adoptedConcordRotations.add("${rejoined.id}:${rejoined.rootEpoch}")) return ConcordInviteResult.Joined(bundle.communityId)
|
||||
Log.i("Concord") { "Stranded rejoin by explicit invite: ${rejoined.id} -> epoch ${rejoined.rootEpoch}" }
|
||||
joinConcordCommunity(rejoined, inviteCreator, inviteLabel, planeWraps)
|
||||
if (!joinConcordCommunity(rejoined, inviteCreator, inviteLabel, planeWraps)) return ConcordInviteResult.NotSaved
|
||||
_strandedConcordCommunities.value -= rejoined.id
|
||||
return ConcordInviteResult.Joined(bundle.communityId)
|
||||
}
|
||||
@@ -715,7 +720,7 @@ class AccountConcordActions(
|
||||
// recoverStrandedConcordCommunities().
|
||||
inviteRef = ConcordActions.bareInviteRef(url),
|
||||
)
|
||||
joinConcordCommunity(entry, inviteCreator, inviteLabel, planeWraps)
|
||||
if (!joinConcordCommunity(entry, inviteCreator, inviteLabel, planeWraps)) return ConcordInviteResult.NotSaved
|
||||
return ConcordInviteResult.Joined(bundle.communityId)
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -69,4 +69,11 @@ sealed interface ConcordInviteResult {
|
||||
* bundle format this app can't read yet. Retrying can't help.
|
||||
*/
|
||||
data object Incompatible : ConcordInviteResult
|
||||
|
||||
/**
|
||||
* The invite was good, but the membership could not be written to the Community List: the
|
||||
* List is not loaded yet, or every fragment this device holds is full while the rest are
|
||||
* missing (CORD-02 §8). Nothing was announced. Retrying can help once the List loads.
|
||||
*/
|
||||
data object NotSaved : ConcordInviteResult
|
||||
}
|
||||
|
||||
@@ -3614,7 +3614,7 @@
|
||||
<string name="concord_channel_rename_save">Rename</string>
|
||||
<string name="concord_channels_empty">No channels yet.</string>
|
||||
<string name="concord_create_action">Create</string>
|
||||
<string name="concord_create_failed">No relay accepted the new community, so it was not created. Check the relays and try again.</string>
|
||||
<string name="concord_create_failed">The community could not be created: no relay accepted it, or your community list could not be updated. Check the relays and try again.</string>
|
||||
<string name="concord_create_relays">Relays</string>
|
||||
<string name="concord_create_relays_desc">Relays that store this community's encrypted messages. Leave empty to use your own.</string>
|
||||
<string name="concord_create_title">New Concord Channel</string>
|
||||
@@ -3627,6 +3627,7 @@
|
||||
<string name="concord_invite_failed_expired">This invite link has expired and can no longer be used. Ask for a fresh link.</string>
|
||||
<string name="concord_invite_failed_incompatible">This invite link can't be opened. It may be outdated or already replaced by a newer one, or created with a newer version of the app. Ask for a fresh invite link.</string>
|
||||
<string name="concord_invite_failed_invalid">This invite link is invalid or can't be opened with this account.</string>
|
||||
<string name="concord_invite_failed_not_saved">The invite works, but your community list could not be updated, so you were not joined. Try again in a moment.</string>
|
||||
<string name="concord_invite_failed_revoked">This invite link has been revoked and can no longer be used. Ask for a new one.</string>
|
||||
<string name="concord_invite_links_action">Invite links…</string>
|
||||
<string name="concord_invite_links_title">Invite links</string>
|
||||
|
||||
+3
@@ -52,6 +52,7 @@ import com.vitorpamplona.amethyst.commons.resources.concord_invite_failed_banned
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_failed_expired
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_failed_incompatible
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_failed_invalid
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_failed_not_saved
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_failed_revoked
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_preview_explainer
|
||||
import com.vitorpamplona.amethyst.commons.resources.concord_invite_preview_relays
|
||||
@@ -144,6 +145,8 @@ fun ConcordInviteScreen(
|
||||
RedeemState.Failed(Res.string.concord_invite_failed_expired, canRetry = false)
|
||||
is ConcordInviteResult.NotReachable ->
|
||||
RedeemState.Failed(Res.string.concord_invite_failed, canRetry = true)
|
||||
is ConcordInviteResult.NotSaved ->
|
||||
RedeemState.Failed(Res.string.concord_invite_failed_not_saved, canRetry = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user