simplify: remove sub-tabs, starred, feed filter chips from Reader
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

Reader now shows only unread entries. Removed:
- Unread/Starred/All sub-tab selector
- Feed filter chip bar (categories)
- All related state (selectedSubTab) and helpers

Glass nav bar shows: "Reader" title + "74 unread" subtitle
Trailing toolbar: grid/list toggle + ellipsis menu
Auto-scroll: speed controls in leading toolbar

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yusuf Suleman
2026-04-04 10:07:40 -05:00
parent d75fb870d7
commit 0f1a35ab84

View File

@@ -4,7 +4,6 @@ struct ReaderTabView: View {
@Bindable var vm: ReaderViewModel
@Binding var isAutoScrolling: Bool
@Binding var scrollSpeed: Double
@State private var selectedSubTab = 0
@State private var showFeedSheet = false
@State private var showFeedManagement = false
@State private var isCardView = true
@@ -43,29 +42,7 @@ struct ReaderTabView: View {
}
}
} else {
// Normal mode: sub-tabs + controls
ToolbarItemGroup(placement: .topBarLeading) {
ForEach(Array(subTabs.enumerated()), id: \.offset) { index, tab in
Button {
withAnimation(.easeInOut(duration: 0.2)) {
selectedSubTab = index
switch index {
case 0: vm.applyFilter(.unread)
case 1: vm.applyFilter(.starred)
case 2: vm.applyFilter(.all)
default: break
}
}
} label: {
Text(tab)
.fontWeight(selectedSubTab == index ? .semibold : .regular)
}
.tint(selectedSubTab == index ? Color.accentWarm : Color.textSecondary)
}
}
ToolbarSpacer(.fixed, placement: .topBarTrailing)
// Normal mode: controls
ToolbarItemGroup(placement: .topBarTrailing) {
Button {
withAnimation(.easeInOut(duration: 0.2)) {
@@ -107,33 +84,6 @@ struct ReaderTabView: View {
}
}
// Feed filter chips bottom toolbar (scrolls with content)
ToolbarItem(placement: .bottomBar) {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 8) {
feedFilterChip("All", isSelected: isAllSelected) {
let tab = selectedSubTab
switch tab {
case 0: vm.applyFilter(.unread)
case 1: vm.applyFilter(.starred)
case 2: vm.applyFilter(.all)
default: vm.applyFilter(.unread)
}
}
ForEach(vm.feeds) { feed in
let count = vm.counters?.count(forFeed: feed.id) ?? 0
feedFilterChip(
feed.title,
count: selectedSubTab == 0 ? count : nil,
isSelected: vm.currentFilter == .feed(feed.id)
) {
vm.applyFilter(.feed(feed.id))
}
}
}
}
}
}
.sheet(isPresented: $showFeedSheet) {
AddFeedSheet(vm: vm)
@@ -145,46 +95,8 @@ struct ReaderTabView: View {
.onAppear {
ArticleRenderer.shared.reWarmIfNeeded()
}
.onChange(of: selectedSubTab) { _, _ in
isAutoScrolling = false
}
.onChange(of: vm.currentFilter) { _, _ in
isAutoScrolling = false
}
}
// MARK: - Helpers
private var subTabs: [String] { ["Unread", "Starred", "All"] }
private var isAllSelected: Bool {
switch vm.currentFilter {
case .unread, .starred, .all: return true
default: return false
}
}
private func feedFilterChip(
_ title: String,
count: Int? = nil,
isSelected: Bool,
action: @escaping () -> Void
) -> some View {
Button(action: action) {
HStack(spacing: 4) {
Text(title)
.font(.caption.weight(isSelected ? .semibold : .regular))
.lineLimit(1)
if let count, count > 0 {
Text("\(count)")
.font(.system(size: 10).weight(.bold))
}
}
.foregroundStyle(isSelected ? Color.accentWarm : Color.textSecondary)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(isSelected ? Color.accentWarm.opacity(0.12) : Color.surfaceCard)
.clipShape(Capsule())
}
}
}