Skip to Content
Usage GuideApp Features

App Features

Solidarity uses three main tabs to organize all functionality. Below is the screen structure, key components, and corresponding code for each tab.

Tab Structure

┌──────────────┬──────────────┬──────────────┐ │ People │ Share │ Me │ │ person.2 │ qrcode │ person.text │ │ .fill │ .viewfinder │ .rectangle │ └──────────────┴──────────────┴──────────────┘

Code: solidarity/Views/Common/MainTabView.swift

TabViewDescription
PeoplePeopleListView.swiftContact list, face-to-face exchange entry
ShareSharingTabView.swiftQR Code display + proximity radar
MeMeTabView.swiftIdentity credential management, proof presentation

The QR Scanner is in the top-left of Share Tab → ScanTabView.swift.


Tab 1 — People

Main Screen [PL-1] People List

┌─ Navigation Bar ────────────────────────┐ │ People [+] [↔ Exchange] │ ├─────────────────────────────────────────┤ │ 🔍 Search │ ├─ Verified ──────────────────────────────┤ │ 👤 Mei ✅ 2025-03-15 │ │ Sprout Labs · Designer │ │ "Met at DID workshop!" │ ├─ Contacts ──────────────────────────────┤ │ 👤 Alice Wang │ │ (imported from phone contacts) │ └──────────────────────────────────────────┘

Components:

  • Verified section — contacts exchanged face-to-face (isVerified = true), shows exchange date and ephemeral message snippet
  • Contacts section — imported or manually added contacts
  • [↔ Exchange] → EX-1 Discovery (face-to-face exchange flow)
  • [+] → PL-3 manually add contact

Empty states:

  • No contacts at all [PL-1e] → CTA “Import phone contacts”
  • Has contacts but no verified [PL-1v] → “No face-to-face verified contacts yet” + [Exchange Cards]

Code: solidarity/Views/PeopleViews/PeopleListView.swift


Person Detail [PL-2]

┌─ Navigation Bar ────────────────────────┐ │ [← Back] Mei [Share] [Edit] │ ├──────────────────────────────────────────┤ │ [Avatar] │ │ Mei │ │ Sprout Labs · Product Designer │ │ ✅ Verified · 2025-03-15 │ │ 📍 ETHGlobal Taipei │ ├─ Ephemeral Message ─────────────────────┤ │ 💬 You wrote to Mei: │ │ "Met at DID workshop!" │ │ 💬 Mei wrote to you: │ │ "Great meeting you! 🙌" │ ├─ Contact Info ──────────────────────────┤ │ 📧 mei@sprout.tw │ │ 📱 0912-345-678 │ │ 🔗 linkedin.com/in/mei │ ├─ Actions ───────────────────────────────┤ │ [Call] [Email] [Share Contact] │ └──────────────────────────────────────────┘

The ephemeral message section only appears for isVerified = true contacts.


Tab 2 — Share

Main Screen SharingTabView

┌─ Navigation Bar ──────────────────────────┐ │ [📷 Scan] Share │ ├────────────────────────────────────────────┤ │ │ │ [Your Business Card QR Code] │ │ │ │ ┌─────────────────────────────────┐ │ │ │ [QR Code] │ │ │ └─────────────────────────────────┘ │ │ │ │ Ming · Acme Corp │ │ │ │ [Radar / Nearby] [Share Link] │ └────────────────────────────────────────────┘

Components:

  • QR Code display — outputs one of three formats based on sharingFormat
  • [📷 Scan] — top-left scanner entry → ScanTabView
  • [Radar] — launch proximity matching → MatchingView

Code:

  • solidarity/Views/SharingViews/SharingTabView.swift
  • solidarity/Services/Card/QRCodeGenerationService.swift
  • solidarity/Views/MatchViews/MatchingView.swift

QR Scanner [SC-1] ScanTabView

┌──────────────────────────────────────────┐ │ [Full-screen camera] │ │ │ │ ┌────────────┐ │ │ │ QR frame │ │ │ └────────────┘ │ │ │ │ Scan QR Code │ │ Present proof · Receive credential │ │ · Verify others │ └──────────────────────────────────────────┘

QR Router [SC-2] — parses QR payload and routes:

QR PrefixActionTarget Screen
openid4vp://Present ProofPR-1 Proof Request Review
VP token (JWT)Verify ProofVF-1 Verification Result
solidarity-verify://Self-hosted verifier deep linkVF-1
VCF formatAdd contactPL-3 pre-filled
UnrecognizedErrorinline toast

Code: solidarity/Views/ScanViews/ScanTabView.swift, solidarity/Services/Card/QRCodeScanService.swift


Tab 3 — Me

Main Screen [Me-1] Me Overview

┌─ Navigation Bar ────────────────────────┐ │ My Identity [⚙️] │ ├──────────────────────────────────────────┤ │ [Avatar] │ │ Ming │ │ did:key:z6Mk... (tap to reveal) │ ├─ My Identity Cards ────────────────────┤ │ ┌───────────────────────────────────┐ │ │ │ 🛂 Passport 🟢 Government │ │ │ │ Trust: ROC Ministry of Foreign │ │ │ │ Affairs · ZKP Verified ✓ │ │ │ │ [View Details →] │ │ │ └───────────────────────────────────┘ │ │ ┌───────────────────────────────────┐ │ │ │ 🕸️ Social Graph ⚪ Self-Issued │ │ │ │ 47 face-to-face verified contacts │ │ │ │ [View Details →] │ │ │ └───────────────────────────────────┘ │ ├─ What I Can Prove ─────────────────────┤ │ ┌───────────────────────────────────┐ │ │ │ 🟢 I'm 18+ [Present →]│ │ │ │ Source: Passport · ZKP │ │ │ ├───────────────────────────────────┤ │ │ │ 🟢 I'm a real human [Present →]│ │ │ │ Source: Passport · ZKP │ │ │ └───────────────────────────────────┘ │ ├─ Add More ─────────────────────────────┤ │ [+ Scan Passport] [+ Import Credential]│ └──────────────────────────────────────────┘

Trust level badges:

  • 🟢 Government — passport ZKP verified
  • 🔵 Institution — institution-issued VC (v2)
  • ⚪ Self-issued — social graph and other self-issued VCs

[Present →] → [PR-1b] Self-Initiated QR Display, shows Smart QR for verifier to scan.

Code: solidarity/Views/MeViews/MeTabView.swift


Settings [ST-1] (accessed via ⚙️ in Me Tab)

┌─ Navigation Bar ────────────────────────┐ │ [← Back] Settings │ ├─ Account ───────────────────────────────┤ │ Device key: ✅ Created │ │ Cross-device sync: ✅ iCloud Keychain │ ├─ Security ──────────────────────────────┤ │ Social Recovery: ✅ Set (5 guardians) │ ├─ Backup ────────────────────────────────┤ │ iCloud Backup [Toggle] │ ├─ Import / Export ──────────────────────┤ │ [Import VCF Contacts] │ │ [Export All Data] → Face ID confirm │ │ [Export Social Graph] → Face ID confirm │ ├─ Advanced ──────────────────────────────┤ │ [View My DIDs] │ │ [Regenerate ZK Proof] │ └──────────────────────────────────────────┘

Code: solidarity/Views/SettingsViews/ (multiple settings screens)


Data Models

Contact

// solidarity/Models/Contact.swift @Model class Contact { var name: String var isVerified: Bool = false // true only for face-to-face exchanges var verifiedAt: Date? var didPublicKey: String? // peer's DID public key var exchangeSignature: Data? // peer's exchange signature var myExchangeSignature: Data? // my exchange signature (for Graph Export) var myEphemeralMessage: String? // message I wrote to them var theirEphemeralMessage: String? // message they wrote to me var source: String // "imported" | "exchanged" | "manual" }

IdentityCard

// solidarity/Models/IdentityEntities.swift @Model class IdentityCard { var type: String // "passport" | "socialGraph" | "imported" var trustLevel: String // "government" | "institution" | "selfIssued" var issuerName: String // "ROC Ministry of Foreign Affairs" var verificationMethod: String // "ZKP Verified" | "NFC Verified" var rawVC: Data // serialized W3C VC }

Screen ID Index (42 screens)

IDScreenTab / ContextPriority
O-1 ~ O-5Onboarding flowOnboardingP0/P1
PL-1, PL-1e, PL-1vPeople ListPeopleP0
PL-2, PL-3Person Detail / Add ContactPeopleP0
EX-1 ~ EX-5Face-to-face exchange flowPeople (modal)P0
SC-1, SC-2Scan Camera + RouterShareP0
VF-1, VF-1c, VF-WVerification resultsShared ModalP0
Me-1, Me-1e, Me-2, Me-3Me overview + credential detailMeP0/P1
PP-1 ~ PP-4Passport Scan sub-flowShared ModalP0
PR-1, PR-1b, PR-2, PR-3Proof presentation flowShared ModalP0
GR-1, GR-2Social Graph credential + exportMe / ModalP0/P1
SR-1, SR-2, SR-3Social RecoveryShared ModalP1
ST-1SettingsMe (push)P1
Last updated on