initial commit: Proximity iOS app proposal, full Swift code scaffold, reference backend, testing docs, generated Xcode project

This commit is contained in:
2026-08-12 00:22:01 +00:00
commit 9d1b0f8dd9
52 changed files with 6271 additions and 0 deletions

View File

@@ -0,0 +1,94 @@
import SwiftUI
/// The emotional centerpiece of the app: the **reveal moment**.
///
/// Two strangers who were physically near each other both chose to be seen.
/// Their silhouettes resolve into people. This screen is deliberately
/// ceremonial it's the payoff for being present in the real world, and it
/// should feel like it.
///
/// The interaction is framed as a physical act: you were *near* this person,
/// you both *waved*, and now you *see* each other. The copy and motion are
/// designed to make this feel significant, not like a notification.
struct RevealView: View {
@EnvironmentObject private var revealFlow: RevealFlow
@Environment(\.dismiss) private var dismiss
@State private var isRevealing = false
@State private var showProfileImport = false
var body: some View {
VStack(spacing: 32) {
Spacer()
// The two avatars converging.
ZStack {
// "You" avatar (left)
avatar(systemImage: "person.fill", offset: isRevealing ? -70 : -110)
// "Them" avatar (right) resolves from silhouette to person.
avatar(systemImage: "person.fill", offset: isRevealing ? 70 : 110)
}
.frame(height: 160)
// Status text
VStack(spacing: 12) {
Text(isRevealing ? "You both waved." : "You're connected.")
.font(.title.bold())
Text(isRevealing
? "Two people who were near each other chose to be seen."
: "You can now say hello.")
.font(.subheadline)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
}
Spacer()
// Actions
VStack(spacing: 12) {
Button {
revealFlow.proceedToConversation()
showProfileImport = true
} label: {
Label("Say hello", systemImage: "bubble.left.and.bubble.right")
.frame(maxWidth: .infinity)
.padding()
}
.buttonStyle(.borderedProminent)
.tint(.green)
Button("Not now") {
dismiss()
}
.foregroundColor(.secondary)
}
.padding(.horizontal)
.padding(.bottom, 24)
}
.onAppear {
// Animate the convergence on appear.
withAnimation(.easeInOut(duration: 1.2)) {
isRevealing = true
}
}
.sheet(isPresented: $showProfileImport) {
if let connection = revealFlow.revealedConnection {
ProfileImportSheet(connection: connection)
}
}
}
private func avatar(systemImage: String, offset: CGFloat) -> some View {
ZStack {
Circle()
.fill(Color.green.opacity(0.2))
.frame(width: 110, height: 110)
Image(systemName: systemImage)
.font(.system(size: 48))
.foregroundColor(.green)
}
.offset(x: offset)
.animation(.easeInOut(duration: 1.2), value: isRevealing)
}
}