Replace page nav arrows with segmented indicator + square chevron

Three amber/gray capsule pills show the current page; a small
rounded-square button with an amber border advances to the next page.
Positioned below the status message (between heroView and the scroll
content), replacing the old left/right chevron bar at the bottom.

Co-Authored-By: Kutesir <kutesir@provoc.ug>
Co-Authored-By: Sentry <sentry@provoc.ug>
This commit is contained in:
Robin Kutesa
2026-05-21 13:44:24 +03:00
parent e8f47fd734
commit 0fd025de3e

View File

@@ -61,17 +61,16 @@ struct BackupView: View {
heroView heroView
.animation(.spring(response: 0.4, dampingFraction: 0.85), value: ringPage) .animation(.spring(response: 0.4, dampingFraction: 0.85), value: ringPage)
// Page indicator
pageIndicator
.padding(.bottom, 8)
// Scrollable stats / detail // Scrollable stats / detail
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
belowContent belowContent
.padding(.bottom, 16) .padding(.bottom, 24)
} }
.refreshable { await triggerRefreshAndBackup() } .refreshable { await triggerRefreshAndBackup() }
// Page navigation
pageNav
.padding(.horizontal, AppTheme.hPad)
.padding(.bottom, 24)
} }
// Menu button floats above scroll content // Menu button floats above scroll content
@@ -679,7 +678,7 @@ struct BackupView: View {
circleStatusRow circleStatusRow
.padding(.horizontal, AppTheme.hPad) .padding(.horizontal, AppTheme.hPad)
.padding(.bottom, 20) .padding(.bottom, 10)
} else { } else {
// Match page 0 spacing so the ring stays at the same Y // Match page 0 spacing so the ring stays at the same Y
Color.clear.frame(height: 60) Color.clear.frame(height: 60)
@@ -929,45 +928,40 @@ struct BackupView: View {
.padding(.bottom, 8) .padding(.bottom, 8)
} }
// MARK: Page navigation // MARK: Page indicator
private var pageNav: some View { private var pageIndicator: some View {
HStack { VStack(spacing: 9) {
Button { // Segmented bar one pill per page, active = amber
withAnimation(.spring(response: 0.4, dampingFraction: 0.85)) { HStack(spacing: 5) {
ringPage = (ringPage - 1 + ringPageCount) % ringPageCount ForEach(0..<ringPageCount, id: \.self) { i in
Capsule()
.fill(i == ringPage
? Color(red: 1.0, green: 0.58, blue: 0.0)
: Color(red: 0.78, green: 0.78, blue: 0.78).opacity(0.4))
.frame(width: 26, height: 2)
.animation(.spring(response: 0.35, dampingFraction: 0.8), value: ringPage)
} }
} label: {
Image(systemName: "chevron.left")
.font(.system(size: 10, weight: .medium))
.foregroundStyle(AppTheme.inkTertiary)
.frame(width: 30, height: 30)
.background(AppTheme.surfaceSunken)
.clipShape(Circle())
} }
Spacer() // Square advance button with amber border
Text(ringPageNames[ringPage])
.font(.system(size: 8, weight: .regular, design: .monospaced))
.foregroundStyle(AppTheme.inkTertiary)
.tracking(2)
Spacer()
Button { Button {
withAnimation(.spring(response: 0.4, dampingFraction: 0.85)) { withAnimation(.spring(response: 0.4, dampingFraction: 0.85)) {
ringPage = (ringPage + 1) % ringPageCount ringPage = (ringPage + 1) % ringPageCount
} }
} label: { } label: {
Image(systemName: "chevron.right") Image(systemName: "chevron.down")
.font(.system(size: 10, weight: .medium)) .font(.system(size: 9, weight: .medium))
.foregroundStyle(AppTheme.inkTertiary) .foregroundStyle(AppTheme.inkSecondary)
.frame(width: 30, height: 30) .frame(width: 30, height: 30)
.background(AppTheme.surfaceSunken) .overlay(
.clipShape(Circle()) RoundedRectangle(cornerRadius: 7, style: .continuous)
.stroke(Color(red: 1.0, green: 0.58, blue: 0.0).opacity(0.55), lineWidth: 1)
)
} }
.buttonStyle(.plain)
} }
.frame(maxWidth: .infinity)
} }
// MARK: Storage helpers // MARK: Storage helpers