feat: auto-scroll speed cycles via tab bar button (Slow/Med/Fast)
All checks were successful
Security Checks / dependency-audit (push) Successful in 13s
Security Checks / secret-scanning (push) Successful in 4s
Security Checks / dockerfile-lint (push) Successful in 4s

Tab bar action button cycles through speeds on each tap:
- ▶ (play) → tap → Slow (1.5x, hare icon)
- Slow → tap → Med (1.75x, walk icon)
- Med → tap → Fast (2.0x, bolt icon)
- Fast → tap → back to Slow

Touch feed to stop → icon returns to ▶

Removed speed controls from Reader toolbar — all speed control
is now in the single tab bar button. Clean, no overlays.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yusuf Suleman
2026-04-04 10:28:03 -05:00
parent e0ae9cb95f
commit 01c63d69d0
2 changed files with 34 additions and 31 deletions

View File

@@ -29,21 +29,41 @@ struct MainTabView: View {
@State private var confettiTrigger = 0 @State private var confettiTrigger = 0
@State private var readerVM = ReaderViewModel() @State private var readerVM = ReaderViewModel()
@State private var isAutoScrolling = false @State private var isAutoScrolling = false
@State private var scrollSpeed: Double = 1.0 @State private var scrollSpeed: Double = 1.5
@State private var speedLevel = 0 // 0=slow, 1=med, 2=fast
@State private var previousTab = 0 @State private var previousTab = 0
private var showReader: Bool { private var showReader: Bool {
auth.currentUser?.id != 4 auth.currentUser?.id != 4
} }
// Dynamic icon for the search-role tab based on context private let speedLevels: [(String, String, Double)] = [
("Slow", "hare", 1.5),
("Med", "figure.walk", 1.75),
("Fast", "bolt.fill", 2.0),
]
// Dynamic icon + label for the search-role tab
private var actionIcon: String { private var actionIcon: String {
if selectedTab == 2 && isAutoScrolling {
return speedLevels[speedLevel].1
}
if selectedTab == 2 { if selectedTab == 2 {
return isAutoScrolling ? "pause.fill" : "play.fill" return "play.fill"
} }
return "plus" return "plus"
} }
private var actionLabel: String {
if selectedTab == 2 && isAutoScrolling {
return speedLevels[speedLevel].0
}
if selectedTab == 2 {
return "Play"
}
return "Add"
}
var body: some View { var body: some View {
ZStack { ZStack {
TabView(selection: $selectedTab) { TabView(selection: $selectedTab) {
@@ -67,7 +87,7 @@ struct MainTabView: View {
Tab(value: 3, role: .search) { Tab(value: 3, role: .search) {
Color.clear Color.clear
} label: { } label: {
Label("Action", systemImage: actionIcon) Label(actionLabel, systemImage: actionIcon)
} }
} }
.tint(Color.accentWarm) .tint(Color.accentWarm)
@@ -119,9 +139,15 @@ struct MainTabView: View {
private func handleActionTap(from sourceTab: Int) { private func handleActionTap(from sourceTab: Int) {
if sourceTab == 2 { if sourceTab == 2 {
// Reader: toggle auto-scroll, return to Reader if !isAutoScrolling {
withAnimation(.spring(duration: 0.3)) { // First tap: start at Slow
isAutoScrolling.toggle() speedLevel = 0
scrollSpeed = speedLevels[0].2
isAutoScrolling = true
} else {
// Cycle: Slow Med Fast Slow
speedLevel = (speedLevel + 1) % speedLevels.count
scrollSpeed = speedLevels[speedLevel].2
} }
selectedTab = 2 selectedTab = 2
} else { } else {

View File

@@ -24,28 +24,7 @@ struct ReaderTabView: View {
.navigationSubtitle(subtitleText) .navigationSubtitle(subtitleText)
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
if isAutoScrolling { ToolbarItemGroup(placement: .topBarTrailing) {
// Auto-scroll mode: speed controls in toolbar
ToolbarItemGroup(placement: .topBarLeading) {
Button {
scrollSpeed = max(0.25, scrollSpeed - 0.25)
} label: {
Image(systemName: "minus")
}
Text(String(format: "%.2fx", scrollSpeed))
.font(.body.weight(.bold).monospacedDigit())
.foregroundStyle(Color.textPrimary)
Button {
scrollSpeed = min(3.0, scrollSpeed + 0.25)
} label: {
Image(systemName: "plus")
}
}
} else {
// Normal mode: controls
ToolbarItemGroup(placement: .topBarTrailing) {
Button { Button {
withAnimation(.easeInOut(duration: 0.2)) { withAnimation(.easeInOut(duration: 0.2)) {
isCardView.toggle() isCardView.toggle()
@@ -84,8 +63,6 @@ struct ReaderTabView: View {
Image(systemName: "ellipsis") Image(systemName: "ellipsis")
} }
} }
}
} }
.sheet(isPresented: $showFeedSheet) { .sheet(isPresented: $showFeedSheet) {
AddFeedSheet(vm: vm) AddFeedSheet(vm: vm)