redesign iOS round into fullscreen swipe flow
This commit is contained in:
@@ -1,37 +1,36 @@
|
||||
import SwiftUI
|
||||
|
||||
enum HermesAppMode: String {
|
||||
case demo
|
||||
case live
|
||||
}
|
||||
|
||||
struct RootView: View {
|
||||
@StateObject private var localization = LocalizationStore()
|
||||
@EnvironmentObject private var analytics: HermesAnalyticsClient
|
||||
@EnvironmentObject private var repository: HermesRepository
|
||||
|
||||
let onStartSession: (String) -> Void
|
||||
let mode: HermesAppMode
|
||||
let onModeSelected: (HermesAppMode) -> Void
|
||||
let onStartSession: (String, HermesAppMode) -> Void
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 24) {
|
||||
header
|
||||
OnboardingView(onStartSession: { onStartSession(localization.localeCode) })
|
||||
FeedView(onRetry: { onStartSession(localization.localeCode) })
|
||||
RoundView(onRetry: { onStartSession(localization.localeCode) })
|
||||
SessionView(onRetry: { onStartSession(localization.localeCode) })
|
||||
SettingsView()
|
||||
}
|
||||
.padding(.horizontal, HermesTheme.screenPadding)
|
||||
.padding(.vertical, 24)
|
||||
}
|
||||
.background(HermesTheme.background.ignoresSafeArea())
|
||||
.navigationTitle(localization.string(for: "app.name"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
ZStack(alignment: .top) {
|
||||
HermesTheme.background
|
||||
.ignoresSafeArea()
|
||||
|
||||
RoundView(onRetry: { onStartSession(localization.localeCode, mode) })
|
||||
.ignoresSafeArea()
|
||||
|
||||
topChrome
|
||||
}
|
||||
.environmentObject(localization)
|
||||
.onAppear {
|
||||
analytics.track("app_opened", attributes: ["screen_name": "home"])
|
||||
analytics.track("screen_viewed", attributes: ["screen_name": "home"])
|
||||
analytics.track("app_opened", attributes: ["screen_name": "round", "mode": mode.rawValue])
|
||||
analytics.track("screen_viewed", attributes: ["screen_name": "round", "mode": mode.rawValue])
|
||||
}
|
||||
.task(id: localization.localeCode) {
|
||||
onStartSession(localization.localeCode)
|
||||
.task(id: "\(localization.localeCode)-\(mode.rawValue)") {
|
||||
onStartSession(localization.localeCode, mode)
|
||||
}
|
||||
.task {
|
||||
while !Task.isCancelled {
|
||||
@@ -41,20 +40,32 @@ struct RootView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var header: some View {
|
||||
HStack(alignment: .top) {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
private var topChrome: some View {
|
||||
HStack(alignment: .top, spacing: 12) {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(localization.string(for: "app.name"))
|
||||
.font(.largeTitle.bold())
|
||||
.font(.headline.weight(.bold))
|
||||
.foregroundStyle(HermesTheme.textPrimary)
|
||||
Text(localization.string(for: "app.subtitle"))
|
||||
.font(.callout)
|
||||
Text(mode == .demo ? localization.string(for: "mode.demo" ) : localization.string(for: "mode.live"))
|
||||
.font(.caption.weight(.semibold))
|
||||
.foregroundStyle(HermesTheme.textSecondary)
|
||||
}
|
||||
|
||||
Spacer(minLength: 12)
|
||||
|
||||
localeToggle
|
||||
VStack(alignment: .trailing, spacing: 10) {
|
||||
modeToggle
|
||||
localeToggle
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, HermesTheme.screenPadding)
|
||||
.padding(.top, 16)
|
||||
}
|
||||
|
||||
private var modeToggle: some View {
|
||||
HStack(spacing: 8) {
|
||||
modeButton(title: localization.string(for: "mode.demo"), appMode: .demo)
|
||||
modeButton(title: localization.string(for: "mode.live"), appMode: .live)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +76,23 @@ struct RootView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func modeButton(title: String, appMode: HermesAppMode) -> some View {
|
||||
let isSelected = mode == appMode
|
||||
|
||||
return Button {
|
||||
onModeSelected(appMode)
|
||||
analytics.track("mode_changed", attributes: ["mode": appMode.rawValue])
|
||||
} label: {
|
||||
Text(title)
|
||||
.font(.caption.weight(.bold))
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.foregroundStyle(isSelected ? HermesTheme.background : HermesTheme.textPrimary)
|
||||
.background(isSelected ? HermesTheme.accent : HermesTheme.surfaceElevated.opacity(0.9))
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
}
|
||||
|
||||
private func localeButton(title: String, localeCode: String) -> some View {
|
||||
let isSelected = localization.localeCode == localeCode
|
||||
|
||||
@@ -77,7 +105,7 @@ struct RootView: View {
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.foregroundStyle(isSelected ? HermesTheme.background : HermesTheme.textPrimary)
|
||||
.background(isSelected ? HermesTheme.accent : HermesTheme.surfaceElevated)
|
||||
.background(isSelected ? HermesTheme.accent : HermesTheme.surfaceElevated.opacity(0.9))
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user