Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,7 @@ struct AccountConnectionsSection: View {
Group {
if account.isConfigured {
VStack(alignment: .leading, spacing: 12) {
SettingsSectionHeader(
label: "ACCOUNT",
hint: account.isSignedIn
? "Your Macs on other networks"
: "Sign in or create an account for internet connections"
)
SettingsSectionHeader(label: "ACCOUNT")

switch account.phase {
case .signedIn:
Expand Down
26 changes: 6 additions & 20 deletions apps/ios/ADE/Views/Hub/HubComponents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,20 +117,14 @@ struct HubConnectionPill: View {
}
}

private var transportLabel: String? {
guard syncService.connectionHealth.transport.isConnected else { return nil }
return syncTransportBadgeText(routeKind: syncService.lastConnectedRouteKind)
}

private var connectionAccessibilityLabel: String {
let state = switch syncService.connectionHealth.transport {
case .connected: "connected"
case .connecting: "connecting"
case .unreachable: "unreachable"
case .disconnected: "offline"
}
let route = transportLabel.map { ", \($0)" } ?? ""
return "Machine connection: \(label), \(state)\(route)"
return "Machine connection: \(label), \(state)"
}

/// Name of the project currently switching in, if any — drives the progress
Expand Down Expand Up @@ -160,25 +154,17 @@ struct HubConnectionPill: View {
} else {
HStack(spacing: 6) {
Circle().fill(tint).frame(width: 7, height: 7)
VStack(alignment: .leading, spacing: 0) {
Text(label)
.font(.system(.caption, design: .rounded).weight(.semibold))
.foregroundStyle(ADEColor.textPrimary)
.lineLimit(1)
if let transportLabel {
Text(transportLabel)
.font(.caption2.weight(.medium))
.foregroundStyle(ADEColor.textSecondary)
.lineLimit(1)
}
}
Text(label)
.font(.system(.caption, design: .rounded).weight(.semibold))
.foregroundStyle(ADEColor.textPrimary)
.lineLimit(1)
}
.id("machine")
.transition(.opacity)
}
}
.padding(.horizontal, 11)
.padding(.vertical, transportLabel == nil ? 8 : 5)
.padding(.vertical, 8)
.background(ADEColor.cardBackground.opacity(0.62), in: Capsule())
.overlay(Capsule().stroke(ADEColor.border.opacity(0.8), lineWidth: 1))
}
Expand Down
192 changes: 154 additions & 38 deletions apps/ios/ADE/Views/Settings/ConnectionSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ struct ConnectionSettingsView: View {

SettingsPairingSection(
snapshot: presentationModel.pairingSnapshot,
presentedSheet: $presentedSheet
presentedSheet: $presentedSheet,
initiallyExpanded: true
)
}
.padding(.horizontal, 16)
Expand All @@ -64,7 +65,7 @@ struct ConnectionSettingsView: View {

// 2. Connection status.
VStack(alignment: .leading, spacing: 12) {
SettingsSectionHeader(label: "CONNECTION", hint: "Your current Mac connection")
SettingsSectionHeader(label: "CONNECTION")

SettingsConnectionHeader(
snapshot: presentationModel.connectionSnapshot,
Expand Down Expand Up @@ -103,13 +104,60 @@ struct ConnectionSettingsView: View {
SettingsUsageQuotaSection(syncService: syncService)
.padding(.horizontal, 16)

SettingsDiagnosticsSection(snapshot: presentationModel.diagnosticsSnapshot)
.padding(.horizontal, 16)

SettingsPushDeliverySection(
snapshot: presentationModel.pushDeliverySnapshot,
pushService: PushNotificationService.shared
)
VStack(spacing: 8) {
SettingsNavigationRow(
title: "Connection details",
subtitle: "Route and connection performance",
systemImage: "point.3.connected.trianglepath.dotted"
Comment on lines +108 to +111

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Hide connection details until content is available

On a fresh install or before the first successful connection, both connectionRoute and connectionPerformance are nil, but this navigation row remains visible. Opening it produces an entirely empty page because .connection suppresses the About section and the connection section renders only when either value exists; hide or disable the row, or provide a concrete empty state.

AGENTS.md reference: AGENTS.md:L59-L60

Useful? React with 👍 / 👎.

) {
SettingsDestinationPage(title: "Connection details") {
SettingsDiagnosticsSection(
snapshot: presentationModel.diagnosticsSnapshot,
content: .connection
)
}
}

SettingsNavigationRow(
title: "About",
subtitle: "App, machine, and device information",
systemImage: "info.circle"
) {
SettingsDestinationPage(title: "About") {
SettingsDiagnosticsSection(
snapshot: presentationModel.diagnosticsSnapshot,
content: .about
)
}
}

SettingsNavigationRow(
title: "Push delivery",
subtitle: "Notifications and Live Activities",
systemImage: "bell.badge"
) {
SettingsDestinationPage(title: "Push delivery") {
SettingsPushDeliverySection(
snapshot: presentationModel.pushDeliverySnapshot,
pushService: PushNotificationService.shared
)
}
}

SettingsNavigationRow(
title: "Delivery diagnostics",
subtitle: "Push registration and relay status",
systemImage: "stethoscope"
) {
SettingsDestinationPage(title: "Delivery diagnostics") {
SettingsPushDeliverySection(
snapshot: presentationModel.pushDeliverySnapshot,
pushService: PushNotificationService.shared,
content: .diagnostics
)
}
}
}
.padding(.horizontal, 16)
}

Expand Down Expand Up @@ -248,6 +296,73 @@ struct ConnectionSettingsView: View {
}
}

private struct SettingsNavigationRow<Destination: View>: View {
let title: String
let subtitle: String
let systemImage: String
@ViewBuilder let destination: () -> Destination

var body: some View {
NavigationLink(destination: destination) {
HStack(spacing: 14) {
Image(systemName: systemImage)
.font(.system(size: 15, weight: .semibold))
.foregroundStyle(ADEColor.purpleAccent)
.frame(width: 34, height: 34)
.background(
RoundedRectangle(cornerRadius: 10, style: .continuous)
.fill(ADEColor.purpleAccent.opacity(0.14))
)

VStack(alignment: .leading, spacing: 2) {
Text(title)
.font(.body.weight(.medium))
.foregroundStyle(ADEColor.textPrimary)
Text(subtitle)
.font(.caption)
.foregroundStyle(ADEColor.textSecondary)
}

Spacer(minLength: 8)

Image(systemName: "chevron.right")
.font(.system(size: 12, weight: .semibold))
.foregroundStyle(ADEColor.purpleAccent.opacity(0.65))
}
.padding(.horizontal, 14)
.padding(.vertical, 12)
.frame(maxWidth: .infinity, alignment: .leading)
.background(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.fill(ADEColor.surfaceBackground.opacity(0.5))
)
.glassEffect(in: .rect(cornerRadius: 14))
.overlay(
RoundedRectangle(cornerRadius: 14, style: .continuous)
.stroke(ADEColor.glassBorder, lineWidth: 0.75)
)
}
.buttonStyle(ADEScaleButtonStyle())
}
}

private struct SettingsDestinationPage<Content: View>: View {
let title: String
@ViewBuilder let content: () -> Content

var body: some View {
ScrollView {
content()
.padding(.horizontal, 16)
.padding(.vertical, 12)
}
.background(SettingsAuroraBackground().ignoresSafeArea())
.adeNavigationGlass()
.navigationTitle(title)
.navigationBarTitleDisplayMode(.inline)
}
}

struct SettingsConnectionSnapshot: Equatable {
var health: SyncConnectionHealth
var connectionState: RemoteConnectionState
Expand Down Expand Up @@ -804,7 +919,7 @@ struct SettingsMachinesSection: View {
var body: some View {
let all = entries
VStack(alignment: .leading, spacing: 12) {
SettingsSectionHeader(label: "MACHINES", hint: "Macs you can connect to")
SettingsSectionHeader(label: "MACHINES")

if all.isEmpty {
Text("No machines yet. Add one below.")
Expand Down Expand Up @@ -882,39 +997,27 @@ struct SettingsMachinesSection: View {
let tappable = !entry.isCurrent && connectingId == nil

VStack(alignment: .leading, spacing: 0) {
ZStack(alignment: .trailing) {
Button {
connect(entry)
} label: {
MachineRowView(
deviceSymbol: deviceSymbol(entry),
title: entry.name,
routeHint: entry.routeHint,
online: entry.online,
isAuthenticatedCurrent: entry.isCurrent,
statusPill: entry.isCurrent ? .connected : nil,
affordance: rowAffordance(entry, isConnecting: isConnecting),
surface: .row
)
Group {
if tappable {
Button {
connect(entry)
} label: {
machineRowLabel(entry, isConnecting: isConnecting)
}
.buttonStyle(ADEScaleButtonStyle())
} else {
machineRowLabel(entry, isConnecting: isConnecting)
}
.buttonStyle(ADEScaleButtonStyle())
.disabled(!tappable)
.accessibilityLabel("\(entry.name), \(entry.routeHint)")
.accessibilityHint(tappable ? "Connect." : "")

}
.accessibilityLabel("\(entry.name), \(entry.routeHint)")
.accessibilityHint(tappable ? "Connect." : "")
.contextMenu {
if let machine = accountMachine(from: entry) {
Button {
renamingMachine = machine
} label: {
Image(systemName: "pencil")
.font(.system(size: 13, weight: .semibold))
.foregroundStyle(ADEColor.textSecondary)
.frame(width: 44, height: 44)
.contentShape(Rectangle())
Label("Rename", systemImage: "pencil")
}
.buttonStyle(.plain)
.padding(.trailing, 58)
.accessibilityLabel("Rename \(entry.name)")
}
}
.opacity(tappable || entry.isCurrent ? 1 : 0.72)
Expand Down Expand Up @@ -948,6 +1051,19 @@ struct SettingsMachinesSection: View {
}
}

private func machineRowLabel(_ entry: Entry, isConnecting: Bool) -> some View {
MachineRowView(
deviceSymbol: deviceSymbol(entry),
title: entry.name,
routeHint: entry.routeHint,
online: entry.online,
isAuthenticatedCurrent: entry.isCurrent,
statusPill: entry.isCurrent ? .connected : nil,
affordance: rowAffordance(entry, isConnecting: isConnecting),
surface: .row
)
}

private func accountMachine(from entry: Entry) -> AccountMachine? {
guard case .account(let machine) = entry.kind else { return nil }
return machine
Expand Down Expand Up @@ -978,7 +1094,7 @@ struct SettingsMachinesSection: View {
}

private func connect(_ entry: Entry) {
guard connectingId == nil else { return }
guard !entry.isCurrent, connectingId == nil else { return }
connectingId = entry.id
rowErrors[entry.id] = nil
Task { @MainActor in
Expand Down
36 changes: 17 additions & 19 deletions apps/ios/ADE/Views/Settings/SettingsConnectionHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,30 @@ struct SettingsConnectionHeader: View {
pulsing: pulsing,
reduceMotion: reduceMotion
)
VStack(alignment: .leading, spacing: 1) {
HStack(spacing: 7) {
Text(SettingsConnectionPresentation.statusLabel(
for: health,
canReconnectToSavedHost: snapshot.canReconnectToSavedHost
))
.font(.system(.body, design: .rounded).weight(.semibold))
.foregroundStyle(ADEColor.textPrimary)
if health.transport.isConnected,
let routeLabel = syncTransportBadgeText(routeKind: snapshot.routeKind) {
Text(routeLabel)
.font(.caption2.weight(.semibold))
.foregroundStyle(ADEColor.textSecondary)
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background(ADEColor.recessedBackground, in: Capsule())
.overlay(Capsule().stroke(ADEColor.border.opacity(0.7), lineWidth: 0.7))
}
}
VStack(alignment: .leading, spacing: 4) {
Text(SettingsConnectionPresentation.statusLabel(
for: health,
canReconnectToSavedHost: snapshot.canReconnectToSavedHost
))
.font(.system(.body, design: .rounded).weight(.semibold))
.foregroundStyle(ADEColor.textPrimary)
if let detail = stateDetailLine {
Text(detail)
.font(.caption)
.foregroundStyle(ADEColor.textSecondary)
.lineLimit(2)
.fixedSize(horizontal: false, vertical: true)
}
if health.transport.isConnected,
let routeLabel = syncTransportBadgeText(routeKind: snapshot.routeKind) {
Text(routeLabel)
.font(.caption2.weight(.semibold))
.foregroundStyle(ADEColor.textSecondary)
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background(ADEColor.recessedBackground, in: Capsule())
.overlay(Capsule().stroke(ADEColor.border.opacity(0.7), lineWidth: 0.7))
}
}
Spacer(minLength: 0)
SettingsConnectionQuickAction(
Expand Down
Loading