e98dd097a746

add Latest/Toplist/Random pill row to ExploreView with mode-tinted colors and active state

time
2026-07-16 18:25 UTC · 3 months ago
machine
koh2
agent
claude-opus-4-8
session
feed modes latest toplist random
parent
28727ecf1209
1 file Sources/Haven/UI/Views/MainView.swift+55 −1
Sources/Haven/UI/Views/MainView.swift+55 −1
@@ -115,11 +115,65 @@115115             .onChange(of: appState.selectedRatio) { _ in Task { await appState.fetchWallpapers() } }116116             117117             Divider()118-            118+119+            // Feed-mode selector: Latest, Toplist, Random. The active mode is120+            // visually emphasised; taps update appState.feedMode and trigger121+            // a reset fetch via the Combine observer in AppState.122+            HStack(spacing: 10) {123+                ForEach(FeedMode.allCases) { mode in124+                    FeedModePill(mode: mode, isActive: appState.feedMode == mode) {125+                        if appState.feedMode != mode {126+                            appState.feedMode = mode127+                        }128+                    }129+                }130+            }131+            .padding(.horizontal)132+            .padding(.vertical, 10)133+134+            Divider()135+119136             WallpaperGrid(wallpapers: appState.wallpapers, appState: appState) {120137                 Task { await appState.loadMore() }121138             }122139         }140+    }141+}142+143+struct FeedModePill: View {144+    let mode: FeedMode145+    let isActive: Bool146+    let action: () -> Void147+148+    private var tint: Color {149+        switch mode {150+        case .latest: return Color(red: 0.45, green: 0.85, blue: 0.30)   // green151+        case .toplist: return Color(red: 0.85, green: 0.40, blue: 0.85)  // magenta152+        case .random: return Color(red: 0.98, green: 0.55, blue: 0.20)   // orange153+        }154+    }155+156+    var body: some View {157+        Button(action: action) {158+            HStack(spacing: 6) {159+                Image(systemName: mode.systemImage)160+                Text(mode.displayName)161+                    .font(.system(size: 13, weight: .medium))162+            }163+            .padding(.horizontal, 14)164+            .padding(.vertical, 8)165+            .frame(maxWidth: .infinity)166+            .foregroundColor(isActive ? .white : tint)167+            .background(168+                RoundedRectangle(cornerRadius: 10)169+                    .fill(isActive ? tint : Color.clear)170+            )171+            .overlay(172+                RoundedRectangle(cornerRadius: 10)173+                    .stroke(tint.opacity(isActive ? 0 : 0.6), lineWidth: 1.5)174+            )175+        }176+        .buttonStyle(.plain)123177     }124178 }125179 

view file