fix: reliable first-message send, QR routing, auto-lock recovery
Fixes reported by testers and found in an app review: - First message right after install no longer fails. Before the app finished registering with the relay, the outgoing message could crash on a null delivery address. The profile field is now optional and the send path throws a clear "still connecting, try again shortly" error while registration completes in the background. - The QR code and share link now appear only once the delivery address is ready. Previously a link generated before the first connection lacked routing, so the other side could not send the first message. The screen now shows a connecting state and reactively swaps in the QR when ready. - Incomplete contact links are rejected on import instead of failing at first send, with a clear prompt to ask for a fresh link. - Auto-lock no longer silences the app: after locking and unlocking, messaging is restarted (it previously stayed dead until app restart). - Group messages are marked failed on a non-per-member send error instead of hanging in the "sending" state forever. - Hardened the relay client against a rare duplicate connection when toggling Tor or locking mid-connect, and fromShareString now rejects a delivery address of the wrong length. - Pin unifiedpush below 6.2.0 to drop the webcrypto dependency (its native framework lacks LC_ENCRYPTION_INFO and blocked the iOS upload). - Skip Android release lint (network dependency check hangs on the build host and adds no value for a Flutter app).
This commit is contained in:
@@ -17,6 +17,15 @@ class ContactsNotifier extends AsyncNotifier<List<Contact>> {
|
||||
final storage = ref.read(storageProvider);
|
||||
final contacts = await future;
|
||||
|
||||
// Odkaz bez routingu (aid+da) = protistrana ho vytvořila dřív, než měla
|
||||
// hotovou registraci. Přidat takový kontakt = časovaná bomba: první
|
||||
// odeslání spadne na „nemá doručovací adresu". Odmítnout hned s
|
||||
// jasnou hláškou. (Nullable routing má smysl jen na interních příjmových
|
||||
// cestách — roster/_findOrCreateContact —, ne při ručním importu.)
|
||||
if (identity.accountId == null || identity.deliveryAddress == null) {
|
||||
throw const ContactLinkIncompleteError();
|
||||
}
|
||||
|
||||
// Kontrola duplicity
|
||||
if (contacts.any((c) => c.publicIdentity.id == identity.id)) {
|
||||
throw const ContactAlreadyExistsError();
|
||||
|
||||
@@ -23,6 +23,14 @@ final messagingStartProvider = FutureProvider<void>((ref) async {
|
||||
final identity = await ref.watch(identityProvider.future);
|
||||
if (identity == null) return;
|
||||
|
||||
// Po auto-locku se tenhle provider eager-rebuildne (drží ho pushInitProvider)
|
||||
// ještě NAD zamčeným storage → service.start() by spadl na „Storage is
|
||||
// locked" a provider by uvázl v AsyncError (žádný příjem/odeslání až do
|
||||
// killu procesu). Nad zamčeným storage tiše nic nestartuj; po odemčení
|
||||
// se provider invaliduje (viz unlock cesty) a spustí start znovu.
|
||||
final storage = ref.read(storageProvider);
|
||||
if (!storage.isUnlocked) return;
|
||||
|
||||
final service = ref.read(messagingServiceProvider);
|
||||
if (service.isStarted) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user