Commit c3a8954
feat: add feed filter menu with Reddit-style dropdown (#45)
* feat: add filter menu support to feed page
Implement tab filtering functionality similar to Android version, allowing users to filter feed content by different categories (技术, 创意, 好玩, Apple, etc.)
Changes:
- Add FilterMenuView: 3-column grid menu displaying all 13 V2EX tabs
- Update Tab enum: Add displayName() fix, needsLogin(), supportsLoadMore(), tab persistence
- Update FeedState: Add selectedTab and showFilterMenu properties
- Update FeedReducer: Add SelectTab and ToggleFilterMenu actions
- Update TopBar: Display selected tab name with chevron indicator
- Update FeedPage: Integrate FilterMenuView with ZStack overlay
- Restrict load more to "all" tab only (matching V2EX API behavior)
Fixes:
- Tab.displayName() now returns correct values instead of empty string
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: redesign filter menu with Reddit-style dropdown
Changes:
- Change title display: Show "V2EX" for default "all" tab, show tab name for other selections
- Redesign menu as left-aligned dropdown (like Reddit) instead of centered modal
- Add icons for each tab category (house, flame, briefcase, etc.)
- Replace grid layout with vertical list layout
- Add checkmark indicator for selected item
- Improve visual hierarchy with better spacing and typography
- Add subtle shadow and spring animation for smoother transitions
UI improvements:
- Menu now anchors to top-left below title
- Width: 200pt, max height: 450pt
- Each item shows icon + label + checkmark (when selected)
- Selected items have blue accent color with light background
- Better touch targets with full-width clickable areas
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: remove unused columns property in FilterMenuView
The columns property was leftover from the initial grid layout design
and is no longer needed after switching to vertical list layout.
Addresses Copilot review comment.
* fix: filter menu now properly overlays content instead of pushing it down
- Moved filter menu rendering from TopBar to MainPage as an overlay
- FilterMenuView now renders above content with proper z-index stacking
- Removed duplicate overlay logic from FeedPage
- Adjusted FilterMenuView positioning to work as a true overlay
- Menu now appears on top of feed content without affecting layout
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: remove padding between topbar and filter dropdown menu
- Removed .padding(.top, 8) from FilterMenuView to eliminate gap
- Dropdown menu now appears directly connected to the topbar
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add soft haptic feedback when toggling filter dropdown menu
- Added light haptic feedback when tapping title to show/hide menu
- Added haptic feedback when dismissing menu by tapping background
- Added haptic feedback when selecting a menu item
- Provides better tactile response for user interactions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add visual tap feedback to filter menu items
- Added pressed state tracking with @State variable
- Implemented scale effect (0.97x) when pressed for visual feedback
- Added opacity change (0.7) when pressed for better visibility
- Added pressed state background color for clear tap indication
- Used onLongPressGesture with minimumDuration: 0 for immediate feedback
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: extend tap area to full width of filter menu items
- Removed alignment constraint from VStack to allow full width
- Added frame(maxWidth: .infinity) to expand items to container width
- Added contentShape(Rectangle()) to make entire area tappable
- Now clicking anywhere on the menu item row triggers the action
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: critical navigation blocking issue caused by FilterMenuView overlay
The FilterMenuView's ZStack was always present in the view hierarchy and
blocking all touch events even when not visible, preventing users from:
- Opening any feed list items
- Accessing pages from Me tab (Posts, Topics, Favorites, Following, etc.)
Added .allowsHitTesting modifier to only intercept touches when menu is shown.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: navigation completely broken on real device due to FilterMenuView
The FilterMenuView component was always present in view hierarchy even when
hidden, causing NavigationLink gesture conflicts on real devices.
Changes:
- Only render FilterMenuView when actually needed (conditional rendering)
- Removed isShowing check inside FilterMenuView since it's now controlled externally
- Eliminated view hierarchy pollution when menu is not shown
- Fixed navigation for all affected areas:
* Feed list items now open properly
* Me page navigation items work again (Posts, Topics, Favorites, etc.)
This issue only affected real devices, not simulators, due to different
gesture recognition behavior.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: increase tap area for filter menu trigger in navbar
- Added horizontal padding (20pt) to expand clickable area
- Added vertical padding (8pt) for easier tapping
- Added contentShape(Rectangle()) to ensure entire padded area is tappable
- Makes filter menu much easier to trigger, especially on real devices
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: address Copilot PR review comments
- Fixed incorrect copyright year (2025 -> 2024) in FilterMenuView.swift
- Removed unused hidden grid icon from TopBar.swift to reduce code complexity
- Cleaned up dead code that was always hidden
These changes address the automated review feedback while maintaining
all functionality.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: address additional Copilot PR review comments
- Fixed rotation angle logic in TopBar to use conditional assignment instead of continuous increment
- Extracted duplicate login check logic in FilterMenuView into local variable
- Reduced code duplication in FeedReducer by extracting supportsLoadMore() calls into variables
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: revert rotation animation and add progress indicator
- Reverted rotation angle logic to continuous increment for smoother animation
- Added progress view display when switching tabs to improve UX
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: auto-scroll to top when switching filter menu items
- Added scrollToTop state property to FeedState
- Modified FeedReducer to trigger scroll after filter change data loads
- Updated FeedPage to use both state and global scroll triggers
- Ensures users see new content from the beginning after filter change
This improves UX by automatically scrolling the feed list to the top
when users select a different filter category, preventing confusion
from seeing mid-scroll content from the previous filter.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 5c207b1 commit c3a8954
File tree
8 files changed
+399
-98
lines changed- V2er.xcodeproj
- V2er
- State/DataFlow
- Model
- Reducers
- State
- View
- Feed
- Widget
8 files changed
+399
-98
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
168 | 169 | | |
169 | 170 | | |
170 | 171 | | |
| 172 | + | |
171 | 173 | | |
172 | 174 | | |
173 | 175 | | |
| |||
203 | 205 | | |
204 | 206 | | |
205 | 207 | | |
206 | | - | |
207 | 208 | | |
208 | 209 | | |
209 | 210 | | |
| |||
263 | 264 | | |
264 | 265 | | |
265 | 266 | | |
| 267 | + | |
266 | 268 | | |
267 | 269 | | |
268 | 270 | | |
| |||
343 | 345 | | |
344 | 346 | | |
345 | 347 | | |
346 | | - | |
347 | | - | |
348 | | - | |
349 | | - | |
350 | | - | |
351 | | - | |
352 | | - | |
353 | | - | |
354 | 348 | | |
355 | 349 | | |
356 | 350 | | |
| |||
513 | 507 | | |
514 | 508 | | |
515 | 509 | | |
| 510 | + | |
516 | 511 | | |
517 | 512 | | |
518 | 513 | | |
| |||
566 | 561 | | |
567 | 562 | | |
568 | 563 | | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
569 | 572 | | |
570 | 573 | | |
571 | 574 | | |
| |||
930 | 933 | | |
931 | 934 | | |
932 | 935 | | |
| 936 | + | |
933 | 937 | | |
934 | 938 | | |
935 | 939 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
27 | | - | |
28 | | - | |
| 27 | + | |
29 | 28 | | |
30 | | - | |
| 29 | + | |
31 | 30 | | |
32 | | - | |
| 31 | + | |
33 | 32 | | |
34 | | - | |
| 33 | + | |
35 | 34 | | |
36 | | - | |
| 35 | + | |
37 | 36 | | |
38 | | - | |
| 37 | + | |
39 | 38 | | |
40 | | - | |
| 39 | + | |
41 | 40 | | |
42 | | - | |
| 41 | + | |
43 | 42 | | |
44 | | - | |
| 43 | + | |
45 | 44 | | |
46 | | - | |
| 45 | + | |
47 | 46 | | |
48 | | - | |
| 47 | + | |
49 | 48 | | |
50 | | - | |
| 49 | + | |
51 | 50 | | |
52 | | - | |
| 51 | + | |
53 | 52 | | |
54 | | - | |
| 53 | + | |
55 | 54 | | |
56 | | - | |
57 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
58 | 81 | | |
59 | 82 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
26 | 32 | | |
27 | 33 | | |
28 | 34 | | |
29 | 35 | | |
| 36 | + | |
30 | 37 | | |
31 | 38 | | |
32 | 39 | | |
33 | 40 | | |
34 | | - | |
| 41 | + | |
| 42 | + | |
35 | 43 | | |
36 | 44 | | |
37 | 45 | | |
| |||
40 | 48 | | |
41 | 49 | | |
42 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
43 | 61 | | |
44 | 62 | | |
45 | 63 | | |
| |||
53 | 71 | | |
54 | 72 | | |
55 | 73 | | |
56 | | - | |
57 | 74 | | |
58 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
59 | 83 | | |
60 | 84 | | |
| 85 | + | |
61 | 86 | | |
62 | 87 | | |
63 | | - | |
| 88 | + | |
64 | 89 | | |
65 | 90 | | |
66 | 91 | | |
67 | 92 | | |
68 | 93 | | |
69 | 94 | | |
70 | 95 | | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
71 | 102 | | |
72 | 103 | | |
73 | 104 | | |
| |||
98 | 129 | | |
99 | 130 | | |
100 | 131 | | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
101 | 141 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
19 | 22 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
45 | | - | |
| 45 | + | |
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | 49 | | |
50 | | - | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| |||
0 commit comments