-
Notifications
You must be signed in to change notification settings - Fork 48
feat: Display online user count in pull-to-refresh view #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add real-time online user count display in the Feed page pull-to-refresh indicator, fetched from V2EX homepage. Changes: - Add OnlineStatsInfo model to parse online user count from V2EX HTML - Add /onlineStats API endpoint with desktop UA to fetch homepage data - Create FetchOnlineStats action and reducer to handle data flow - Update HeadIndicatorView to display online count (e.g., "2613 人在线") - Modify UpdatableView to pass onlineStats through to HeadIndicatorView - Fetch online stats in parallel with feed data on pull-to-refresh The online user count appears in the pull-to-refresh indicator when users refresh the feed, providing real-time community activity information. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds real-time online user count display to the Feed page's pull-to-refresh indicator. When users pull down to refresh, they can now see the current number of online users (e.g., "2613 人在线") providing real-time activity information about the V2EX community.
- Creates
OnlineStatsInfomodel to parse online user count from V2EX homepage HTML using regex patterns - Adds new
/onlineStatsAPI endpoint with desktop user agent to fetch V2EX homepage - Integrates online stats into Redux data flow with actions and reducers
- Updates pull-to-refresh UI components to display online count when available
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| OnlineStatsInfo.swift | New model for parsing online user count and max record from V2EX homepage HTML |
| Endpoint.swift | Adds /onlineStats endpoint with desktop user agent for fetching homepage |
| FeedState.swift | Adds onlineStats property to store online statistics |
| FeedReducer.swift | Implements FetchOnlineStats actions and reducer logic |
| FeedPage.swift | Initiates parallel fetch of online stats during refresh |
| UpdatableView.swift | Passes online stats through the updatable view hierarchy |
| HeadIndicatorView.swift | Displays online user count in pull-to-refresh indicator |
| project.pbxproj | Adds OnlineStatsInfo.swift to Xcode project |
| private func extractNumber(before keyword: String, from text: String) -> Int? { | ||
| let components = text.components(separatedBy: keyword) | ||
| guard let firstPart = components.first else { return nil } | ||
|
|
||
| // Extract the last number from the text before keyword | ||
| let pattern = "(\\d+)\\s*$" | ||
| guard let regex = try? NSRegularExpression(pattern: pattern) else { return nil } | ||
|
|
||
| let nsText = firstPart as NSString | ||
| let matches = regex.matches(in: firstPart, range: NSRange(location: 0, length: nsText.length)) | ||
|
|
||
| if let match = matches.last, match.numberOfRanges > 1 { | ||
| let numberStr = nsText.substring(with: match.range(at: 1)) | ||
| return Int(numberStr.replacingOccurrences(of: ",", with: "")) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| private func extractNumber(after keyword: String, from text: String) -> Int? { | ||
| let components = text.components(separatedBy: keyword) | ||
| guard components.count > 1 else { return nil } | ||
|
|
||
| let afterPart = components[1] | ||
|
|
||
| // Extract the first number from the text after keyword | ||
| let pattern = "(\\d+)" | ||
| guard let regex = try? NSRegularExpression(pattern: pattern) else { return nil } | ||
|
|
||
| let nsText = afterPart as NSString | ||
| let matches = regex.matches(in: afterPart, range: NSRange(location: 0, length: nsText.length)) | ||
|
|
||
| if let match = matches.first, match.numberOfRanges > 1 { | ||
| let numberStr = nsText.substring(with: match.range(at: 1)) | ||
| return Int(numberStr.replacingOccurrences(of: ",", with: "")) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
Copilot
AI
Oct 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The extractNumber(before:) and extractNumber(after:) methods are defined but not used in the current implementation. These methods create unnecessary code complexity and should be removed since the parsing logic uses direct regex patterns instead.
| private func extractNumber(before keyword: String, from text: String) -> Int? { | |
| let components = text.components(separatedBy: keyword) | |
| guard let firstPart = components.first else { return nil } | |
| // Extract the last number from the text before keyword | |
| let pattern = "(\\d+)\\s*$" | |
| guard let regex = try? NSRegularExpression(pattern: pattern) else { return nil } | |
| let nsText = firstPart as NSString | |
| let matches = regex.matches(in: firstPart, range: NSRange(location: 0, length: nsText.length)) | |
| if let match = matches.last, match.numberOfRanges > 1 { | |
| let numberStr = nsText.substring(with: match.range(at: 1)) | |
| return Int(numberStr.replacingOccurrences(of: ",", with: "")) | |
| } | |
| return nil | |
| } | |
| private func extractNumber(after keyword: String, from text: String) -> Int? { | |
| let components = text.components(separatedBy: keyword) | |
| guard components.count > 1 else { return nil } | |
| let afterPart = components[1] | |
| // Extract the first number from the text after keyword | |
| let pattern = "(\\d+)" | |
| guard let regex = try? NSRegularExpression(pattern: pattern) else { return nil } | |
| let nsText = afterPart as NSString | |
| let matches = regex.matches(in: afterPart, range: NSRange(location: 0, length: nsText.length)) | |
| if let match = matches.first, match.numberOfRanges > 1 { | |
| let numberStr = nsText.substring(with: match.range(at: 1)) | |
| return Int(numberStr.replacingOccurrences(of: ",", with: "")) | |
| } | |
| return nil | |
| } |
V2er/View/Feed/FeedPage.swift
Outdated
| .updatable(autoRefresh: state.showProgressView, hasMoreData: state.hasMoreData, max(state.scrollToTop, scrollTop(tab: .feed)), onlineStats: state.onlineStats) { | ||
| if AccountState.hasSignIn() { | ||
| // Fetch online stats in parallel with feed data | ||
| async let _ = run(action: FeedActions.FetchOnlineStats.Start()) |
Copilot
AI
Oct 18, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using async let _ = discards the result and creates a fire-and-forget task. Consider using Task { await run(...) } to be more explicit about the parallel execution intent and avoid potential compiler warnings.
| async let _ = run(action: FeedActions.FetchOnlineStats.Start()) | |
| Task { await run(action: FeedActions.FetchOnlineStats.Start()) } |
Code Coverage Report ❌Current coverage: 0% |
- Remove unused extractNumber helper methods in OnlineStatsInfo - Use explicit Task syntax for parallel execution instead of async let Co-Authored-By: GitHub Copilot <noreply@github.com>
Code Coverage Report ❌Current coverage: 0% |
Summary
Add real-time online user count display in the Feed page pull-to-refresh indicator.
Changes
/onlineStatsendpoint with desktop UA to fetch V2EX homepageFetchOnlineStatsaction and reducer to manage online stats stateScreenshots
When users pull down to refresh the feed, they can now see the current number of online users in the community, providing real-time activity information.
Technical Details
(\d+)\s*人在线Test Plan
🤖 Generated with Claude Code