Skip to content

fix: Improve update banner UI and version detection#92

Merged
kshivang merged 2 commits intomasterfrom
dev
Dec 7, 2025
Merged

fix: Improve update banner UI and version detection#92
kshivang merged 2 commits intomasterfrom
dev

Conversation

@kshivang
Copy link
Copy Markdown
Owner

@kshivang kshivang commented Dec 7, 2025

Summary

  • Remove duplicate BossTerm menu entry on macOS by moving "Check for Updates..." to the Help menu
  • Fix version detection to read from macOS app bundle Info.plist instead of defaulting to 1.0.0
  • Redesign update banner to match TabBar styling with dark background and compact single-row layout

Changes

  • Main.kt: Remove macOS-specific BossTerm menu, add universal Help menu with Check for Updates
  • Version.kt: Add tryGetMacOSBundleVersion() to read CFBundleShortVersionString from Info.plist
  • UpdateUI.kt: Redesign all banners (UpdateAvailable, DownloadProgress, ReadyToInstall, RestartRequired, Error) with:
    • Dark background matching TabBar (#1E1E1E)
    • Compact layout (~28px height vs ~60px)
    • Smaller fonts (12sp text, 11sp buttons)
    • Accent colors for icons instead of colored backgrounds

Test plan

  • Verify no duplicate BossTerm menu on macOS
  • Check for Updates appears in Help menu on all platforms
  • Update banner displays correct current version from app bundle
  • Update banner matches TabBar background color
  • All banner states render correctly (available, downloading, ready, error)

🤖 Generated with Claude Code

kshivang and others added 2 commits December 7, 2025 11:11
- Remove duplicate BossTerm menu on macOS (move Check for Updates to Help menu)
- Read app version from Info.plist on macOS for accurate version display
- Redesign update banner to match TabBar styling (dark background, compact layout)
- Reduce banner height from ~60px to ~28px with smaller fonts and icons
- Use accent colors for icons instead of colored backgrounds

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@kshivang kshivang merged commit 26c8f78 into master Dec 7, 2025
7 checks passed
@claude
Copy link
Copy Markdown

claude Bot commented Dec 7, 2025

Code Review: PR #92 - Improve update banner UI and version detection

Overall Assessment

This is a well-executed PR that addresses multiple UX improvements. The code quality is solid, the changes are cohesive, and the approach is appropriate for the goals.


Strengths

1. Excellent UI Consistency

  • Banner background color (0xFF1E1E1E) perfectly matches TabBar
  • Accent colors (Blue, Green, Orange, Red) provide visual hierarchy
  • Compact layout (28px height) is more space-efficient than previous 60px

2. Smart Version Detection Logic

  • Properly prioritizes macOS bundle over fallbacks (Version.kt:26-38)
  • Graceful degradation with null-safe error handling
  • Appropriate regex pattern for plist parsing

3. Simplified Menu Structure

  • Removes duplicate macOS-specific BossTerm menu
  • Universal Help menu works across platforms

4. Consistent Layout Pattern

All five banner states follow identical structure - good for maintainability


Issues and Suggestions

1. Minor: Text Overflow Handling (Priority: Low)

Location: UpdateUI.kt:93-102

The UpdateAvailableBanner does not handle long version strings gracefully. Add maxLines and overflow parameters to prevent layout issues with pre-release versions like 1.0.0-beta.3.rc1.

2. Enhancement: XML Parsing Robustness (Priority: Medium)

Location: Version.kt:64-67

Add validation after regex match to ensure we only return version strings that can actually be parsed by Version.parse(). This prevents returning malformed version strings.

3. Potential Issue: File I/O on Main Thread (Priority: Medium)

Location: Version.kt:61-62

CURRENT is a lazy property that reads from disk on first access. If accessed on UI thread during startup, could cause jank. Consider documenting this or making version loading asynchronous.


Security Considerations

No Security Issues Found

  • Path Traversal: Not vulnerable - uses substringBefore() on trusted java.home property
  • Regex DoS: Pattern is simple and bounded - no catastrophic backtracking risk
  • File Access: Reads only from app bundle with try-catch wrapper

Code Quality

Follows BossTerm Conventions

  • Clear KDoc for public APIs
  • Proper error handling with null returns
  • Descriptive function names
  • No backwards-compatibility hacks

Recommendations

Must Fix Before Merge

None - the PR is production-ready as-is.

Should Fix (High Value)

  1. Add version string validation after regex match in tryGetMacOSBundleVersion() at Version.kt:66

Nice to Have

  1. Add maxLines and overflow to banner text (UpdateUI.kt:93-102)
  2. Document file I/O implications of Version.CURRENT access
  3. Consider extracting shared colors to theme file

Final Verdict

Approve with minor suggestions

This PR successfully:

  • Removes duplicate macOS menu
  • Improves version detection accuracy
  • Creates visually cohesive update banners
  • Maintains code quality and follows project conventions

The suggestions above are enhancements, not blockers. The code is well-structured and ready to merge.

Great work on the UI redesign!

@claude
Copy link
Copy Markdown

claude Bot commented Dec 7, 2025

Code Review Summary

Overall, this is a well-structured PR that successfully addresses UI consistency and version detection issues. The changes are clean, focused, and improve the user experience. Here's my detailed feedback:


✅ Strengths

1. Menu Simplification (Main.kt)

  • Great improvement: Removing the duplicate BossTerm menu on macOS and consolidating "Check for Updates" into the Help menu creates a cleaner, more consistent cross-platform experience
  • Code quality: The refactoring reduces platform-specific branching and simplifies menu logic
  • Best practice: Following standard menu conventions (Help menu is universal across platforms)

2. UI/UX Improvements (UpdateUI.kt)

  • Design consistency: New banner design matches TabBar styling (#1E1E1E background)
  • Space efficiency: Compact single-row layout (~28px vs ~60px) is less intrusive
  • Visual hierarchy: Using accent colors for icons (blue, green, orange, red) provides clear status indication without overwhelming colored backgrounds
  • Typography: Smaller fonts (12sp/11sp) are appropriate for status banners

3. Version Detection Enhancement (Version.kt)

  • Problem solved: Reading from Info.plist ensures accurate version display on macOS
  • Fallback strategy: Graceful degradation to system properties/environment variables is solid
  • Error handling: Try-catch with null return is appropriate for this use case

⚠️ Issues & Recommendations

1. Critical: Info.plist Parsing Vulnerability (Version.kt:44-73)

Issue: Reading and parsing entire plist file with regex is fragile and potentially slow.

Problems:

  • readText() loads entire file into memory (line 62)
  • Simple regex parsing doesn't handle plist format variations (comments, CDATA, formatting)
  • No validation of file size before reading
  • Regex pattern assumes specific whitespace formatting

Recommendation: Use proper plist parsing library

// Option 1: Use Process API (macOS native)
private fun tryGetMacOSBundleVersion(): String? {
    return try {
        val isMacOS = System.getProperty("os.name")?.lowercase()?.contains("mac") == true
        if (!isMacOS) return null

        val javaHome = System.getProperty("java.home") ?: return null
        if (javaHome.contains(".app/Contents/")) {
            val appPath = javaHome.substringBefore(".app/Contents/") + ".app"
            val infoPlistPath = "$appPath/Contents/Info.plist"
            
            // Use macOS native plutil or defaults command
            val process = ProcessBuilder(
                "/usr/libexec/PlistBuddy",
                "-c",
                "Print :CFBundleShortVersionString",
                infoPlistPath
            ).start()
            
            val version = process.inputStream.bufferedReader().readText().trim()
            process.waitFor()
            
            if (process.exitValue() == 0 && version.isNotEmpty()) {
                return version
            }
        }
        null
    } catch (e: Exception) {
        null
    }
}

Why this matters: XML parsing with regex is error-prone and listed in OWASP guidelines as an anti-pattern.


2. Minor: Error Swallowing (Version.kt:70-72)

Issue: The catch block silently swallows all exceptions without logging.

Impact: Debugging version detection issues will be difficult in production.

Recommendation: Add minimal logging (even if just to stderr):

} catch (e: Exception) {
    System.err.println("Failed to read macOS bundle version: ${e.message}")
    null
}

3. Performance: Lazy Initialization (Version.kt:26)

Current state: by lazy is good for deferred initialization, but the macOS check happens on every app startup.

Recommendation: Consider if version should be cached at build time instead. The Info.plist approach is runtime discovery, which is correct for packaged apps but adds ~5-10ms startup overhead.

Not a blocker: Current approach is fine, but worth noting for future optimization.


4. Code Style: Inconsistent Button Types (UpdateUI.kt)

Observation: Some buttons changed from Button to TextButton (e.g., "Install Now" at line 190).

Impact: TextButton has different click feedback (no background ripple). This is intentional for the new design, but ensure it's tested for accessibility.

Recommendation: Verify buttons have sufficient contrast and visible focus states for keyboard navigation.


5. Potential Bug: Regex Group Access (Version.kt:66)

Issue: match?.groupValues?.get(1) will throw if regex doesn't have a capture group (though current regex is correct).

Recommendation: Use safer accessor:

return match?.groups?.get(1)?.value

This returns null instead of throwing if group 1 doesn't exist.


🔒 Security Assessment

No Critical Issues Found

  • File path traversal: Not applicable (hardcoded path construction)
  • Command injection: Not applicable (no shell execution in current code)
  • XML External Entity (XXE): Mitigated by not using XML parser (though regex parsing is fragile)

However: If you switch to proper plist parsing, ensure you use a library that disables external entities.


🧪 Test Coverage Recommendations

The PR description includes a test plan, but I recommend adding:

  1. Version.kt Unit Tests:

    • Test tryGetMacOSBundleVersion() with mock file system
    • Test parse() with malformed plist content
    • Test fallback behavior when Info.plist is missing
  2. UpdateUI.kt Visual Regression Tests:

    • Snapshot test for each banner state
    • Verify text doesn't overflow in compact layout
    • Test with long version strings (e.g., "1.0.0-beta.20231215.build12345")
  3. Integration Test:

    • Verify Help menu "Check for Updates" works on all platforms

📊 Performance Impact


🎯 Recommendation Summary

Priority Issue Action
HIGH Info.plist regex parsing Use PlistBuddy or proper XML parser
MEDIUM Silent error swallowing Add logging to catch block
LOW Regex group accessor Use safer .groups?.get(1)?.value
LOW Test coverage Add unit tests for Version.kt

✅ Approval Recommendation

Status: ✅ Approve with suggestions

The PR successfully achieves its goals and the code quality is good. The Info.plist parsing is the only concern, but it's:

  • Non-blocking (has fallback)
  • Unlikely to fail in practice (plist format is stable)
  • Easy to improve in a follow-up PR

Suggested merge strategy: Merge as-is, then create a follow-up issue to improve plist parsing robustness.


Great work on improving the UI consistency! The new banner design is much cleaner. 🎨

kshivang added a commit that referenced this pull request Dec 12, 2025
fix: Improve update banner UI and version detection
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant