-
Notifications
You must be signed in to change notification settings - Fork 47
feat: Add vshare version checking and notification badge #152
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 VshareVersionInfo model for parsing API response - Add VshareVersionChecker with 24-hour caching logic - Add "发现更多" menu item in navigation drawer - Extend BaseToolBar to support navigation icon badges - Show red dot badge on both navigation menu and hamburger icon when updates available - Badge clears when user clicks menu item and views page This feature notifies users when new content is available on the vshare page by displaying a red notification dot on both the navigation menu item and the hamburger menu button. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
- Remove BaseToolBar extension approach that wasn't working properly - Implement LayerDrawable approach to overlay badge on navigation icon - Create navigation icon with embedded red dot badge - Switch between original icon and badged icon based on update status The badge now correctly appears on the hamburger menu icon in the top-left corner. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
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
Adds a vshare version check feature with UI notification badges (red dots) on the navigation drawer item and the toolbar hamburger icon to alert users of new vshare content. Key additions include a version info model, a version checker with 24‑hour caching logic, UI resources (icon, badge layout, shape), and integration into MainActivity and toolbar.
- Adds VshareVersionInfo model and VshareVersionChecker utility
- Adds navigation menu item with badge layout and toolbar badge logic
- Integrates version checking and badge visibility updates in MainActivity
Reviewed Changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| app/src/main/res/values/strings.xml | Adds localized string for the new vshare menu item. |
| app/src/main/res/menu/navigation_menu.xml | Adds vshare navigation item with custom action layout for badge. |
| app/src/main/res/layout/layout_vshare_badge.xml | Defines badge (red dot) layout container. |
| app/src/main/res/drawable/vshare_nav_item.xml | Adds vector icon for vshare menu entry. |
| app/src/main/res/drawable/shape_badge_dot.xml | Adds red dot shape drawable used for badges. |
| app/src/main/java/me/ghui/v2er/widget/BaseToolBar.java | Adds navigation badge support (creation/show/hide logic). |
| app/src/main/java/me/ghui/v2er/util/VshareVersionChecker.java | Implements version checking, caching, and view acknowledgment logic. |
| app/src/main/java/me/ghui/v2er/network/bean/VshareVersionInfo.java | Data model for version response with validation. |
| app/src/main/java/me/ghui/v2er/network/APIs.java | Adds API endpoint for vshare version JSON. |
| app/src/main/java/me/ghui/v2er/module/home/MainActivity.java | Integrates version checker, badge handling for menu and toolbar, and navigation handling. |
| // If server version is newer, return true | ||
| return serverVersion > localVersion; |
Copilot
AI
Oct 16, 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 server version is never persisted here when a newer version is detected, so subsequent checks within 24h fall back to hasUpdate() which always returns false, causing the badge to disappear incorrectly before the user views the content. Persist the serverVersion (e.g. putInt(KEY_LAST_VERSION, serverVersion)) or store a separate 'latest_server_version' and compare it to a 'viewed_version'.
| // If server version is newer, return true | |
| return serverVersion > localVersion; | |
| // If server version is newer, persist it and return true | |
| if (serverVersion > localVersion) { | |
| prefs.edit() | |
| .putInt(KEY_LAST_VERSION, serverVersion) | |
| .apply(); | |
| return true; | |
| } | |
| return false; |
| private boolean hasUpdate() { | ||
| int lastVersion = prefs.getInt(KEY_LAST_VERSION, 0); | ||
| // If we haven't checked yet, assume no update | ||
| if (lastVersion == 0) { | ||
| return false; | ||
| } | ||
| // This would need server version to compare, but we're using cached data | ||
| // In practice, this will be updated by checkForUpdate() | ||
| return false; | ||
| } |
Copilot
AI
Oct 16, 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.
hasUpdate() always returns false, making the cached path (within 24h) ineffective and wiping any pending badge state. Either cache the last known server version separately and compare it to a stored viewed version, or persist a boolean flag indicating an unseen update.
| public void markAsViewed() { | ||
| APIService.get() | ||
| .getVshareVersion() | ||
| .subscribeOn(Schedulers.io()) | ||
| .observeOn(AndroidSchedulers.mainThread()) | ||
| .subscribe(versionInfo -> { | ||
| if (versionInfo != null && versionInfo.isValid()) { | ||
| prefs.edit() | ||
| .putInt(KEY_LAST_VERSION, versionInfo.getVersion()) | ||
| .apply(); | ||
| } | ||
| }, throwable -> { | ||
| // Silently ignore errors | ||
| }); |
Copilot
AI
Oct 16, 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.
[nitpick] markAsViewed() performs an extra network request solely to record a version the app already had when showing the badge. Cache the server version during checkForUpdate() and write it directly here (or pass it in) to avoid an unnecessary call.
| public void showNavigationBadge() { | ||
| // Initialize badge if needed | ||
| if (mNavigationBadge == null) { | ||
| initNavigationBadge(); | ||
| } | ||
|
|
||
| if (mNavigationBadge != null) { | ||
| mNavigationBadge.setVisibility(VISIBLE); | ||
| } |
Copilot
AI
Oct 16, 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.
If mNavigationBadge is null, initNavigationBadge() posts a creation runnable; the badge is created later with GONE visibility and never updated to VISIBLE because this method returns before creation completes. Move the visibility change into the post() block in initNavigationBadge() (conditional flag) or provide a callback so the badge becomes visible after asynchronous creation.
| badgeParams.leftMargin = ScaleUtils.dp(36); // 16dp padding + 24dp icon - 4dp overlap | ||
| badgeParams.topMargin = ScaleUtils.dp(12); // Position at top of icon |
Copilot
AI
Oct 16, 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.
[nitpick] Magic numbers (36, 12) with inline arithmetic commentary reduce clarity and adaptability (e.g., RTL, different toolbar sizes). Extract these to named constants or derive from actual view dimensions at runtime.
| android:paddingEnd="16dp" | ||
| android:paddingRight="16dp"> |
Copilot
AI
Oct 16, 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.
[nitpick] Redundant simultaneous use of paddingEnd and paddingRight; prefer only paddingEnd (and possibly paddingStart) for proper RTL support unless an explicit legacy fallback is required.
| android:paddingEnd="16dp" | |
| android:paddingRight="16dp"> | |
| android:paddingEnd="16dp"> |
| android:layout_height="8dp" | ||
| android:layout_gravity="center_vertical" | ||
| android:background="@drawable/shape_badge_dot" | ||
| android:visibility="gone" /> |
Copilot
AI
Oct 16, 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.
Decorative badge view lacks accessibility suppression; add android:importantForAccessibility="no" (or focusable="false" and contentDescription="") so screen readers do not announce an unlabeled visual element.
| android:visibility="gone" /> | |
| android:visibility="gone" | |
| android:importantForAccessibility="no" /> |
| android:viewportHeight="24"> | ||
| <!-- Share/Discovery icon representing multiple apps/products --> | ||
| <path | ||
| android:fillColor="#757575" |
Copilot
AI
Oct 16, 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.
[nitpick] Hard-coded fillColor may not adapt to light/dark themes or dynamic color; reference a theme attribute or color resource (e.g., ?attr/icon_tint_color) and rely on tinting for consistency.
| android:fillColor="#757575" | |
| android:fillColor="?attr/colorControlNormal" |
| // Position the badge at the top-right corner of the icon | ||
| // Navigation icon is 24dp, badge is 8dp | ||
| mNavIconWithBadge.setLayerSize(1, ScaleUtils.dp(8), ScaleUtils.dp(8)); | ||
| mNavIconWithBadge.setLayerGravity(1, Gravity.TOP | Gravity.END); | ||
| mNavIconWithBadge.setLayerInsetEnd(1, -ScaleUtils.dp(4)); // Overlap with icon edge | ||
| mNavIconWithBadge.setLayerInsetTop(1, -ScaleUtils.dp(4)); // Overlap with icon edge |
Copilot
AI
Oct 16, 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.
[nitpick] Multiple hard-coded dp values and negative insets are brittle; consider computing offsets based on intrinsic sizes (icon + badge) or centralizing these values as named constants to ease future adjustments and ensure compatibility across densities and API levels.
Summary
This PR implements a vshare version checking system with notification badges to inform users when new content is available on the vshare page.
Features Implemented
Technical Details
Visual Changes
Testing
🤖 Generated with Claude Code