-
Notifications
You must be signed in to change notification settings - Fork 900
[PM-25423] Add BidiTextManager for handling bidirectional text #5825
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
|
Great job! No new security vulnerabilities introduced in this pull request |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5825 +/- ##
==========================================
+ Coverage 84.74% 84.78% +0.03%
==========================================
Files 737 720 -17
Lines 55439 55051 -388
Branches 7655 7653 -2
==========================================
- Hits 46983 46675 -308
+ Misses 5775 5695 -80
Partials 2681 2681 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@codokie Can you confirm if the Verification Codes are being handled correctly in the screenshots? If the code is |
fe7a20d to
a4253c9
Compare
It should appear as 123 456. Even though letters are written from right-to-left, Western Arabic numerals are interpreted from left-to-right. I have seen a very few apps which do not take this into consideration and thus expect 456 123 or 654 321 as input. Most localized services consider 123456 as the correct input because they don’t even use a space to divide the verification code. Preferring 456 123 would cause much confusion. By the way, I’m not sure if #5012 handled verification codes correctly because I had used a dummy account w/o Premium for testing. So it’s good thing that you’ve brought this up. |
|
While trying to test this change on my end, I noticed that it did not have any effect unless Having done that, after a brief testing I can say that your minimalistic method fixes most of the issues described in #4753, with the added benefit that it does not cause alignment issues like in #5012. However, I’ve noticed 3 issues that make me doubt if
Video demonstrating points 1 & 2 (click to expand)1.and.2.webmNotice that the caret is incorrectly aligned to the left. The input should have appeared as Video demonstrating point no. 3 (click to expand)3.webmThis happened while trying to write |
a4253c9 to
eff8906
Compare
This commit introduces `BidiTextManager` to manage and ensure correct display of text containing both LTR and RTL characters. It includes: - `BidiTextManager` interface with a `unicodeWrap` method. - `BidiTextManagerImpl` as the default implementation, using `androidx.core.text.BidiFormatter`. - `LocalBidiTextManager` CompositionLocal for providing the manager in Compose UI.
…tting methods using native BidiFormatter - Add forceLtr(), forceRtl(), formatVerificationCode(), formatPhoneNumber(), formatCardNumber() to interface - Implement all methods using BidiFormatter.unicodeWrap() with appropriate TextDirectionHeuristicsCompat: - LTR for forceLtr() - RTL for forceRtl() - ANYRTL_LTR for unicodeWrap() - Add basic unit tests for edge cases (empty string handling) - Full bidi behavior should be tested via instrumentation tests with Android framework
- Create DSL builder function bidiTextManager() to instantiate BidiTextManagerImpl outside ui module - Add BidiTextManager provider to PlatformUiManagerModule for Hilt dependency injection - Follow established pattern from CXF module for internal class instantiation
BidiTextManager foundation ready: - Interface with 6 methods (unicodeWrap, forceLtr, forceRtl, formatVerificationCode, formatPhoneNumber, formatCardNumber) - Implementation using native BidiFormatter with TextDirectionHeuristicsCompat - DSL builder for cross-module instantiation - Hilt DI integration via PlatformUiManagerModule - Unit tests passing Ready to proceed with parallel implementation across 3 workstreams
243603a to
c316882
Compare
…deItem for RTL support
- Apply formatCardNumber() to card number display - Apply forceLtr() to card security code field
…t for RTL support
…xed-script RTL support
… for RTL support Generated with Claude Code Co-Authored-By: Claude <[email protected]>
… for RTL support Generated with Claude Code Co-Authored-By: Claude <[email protected]>
…main support - Added LocalBidiTextManager import and acquisition - Applied unicodeWrap() to URI field display values - Applied unicodeWrap() to URI list display - Ensures proper bidirectional text rendering for domains in RTL contexts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…me for RTL support - Added LocalBidiTextManager import and acquisition - Applied forceLtr() to card expiration for MM/YY format consistency - Applied unicodeWrap() to cardholder name for proper bidirectional rendering - Ensures date formats remain LTR and names render correctly in RTL contexts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…icense, phone, address) for RTL support - Applied forceLtr() to SSN field for directional consistency - Applied unicodeWrap() to passport number for bidirectional rendering - Applied unicodeWrap() to license number for bidirectional rendering - Applied formatPhoneNumber() to phone field for locale-aware formatting - Applied unicodeWrap() to address field for bidirectional rendering - Ensures identity data renders correctly in RTL and LTR contexts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ration Resolve conflicting declarations from workstream merges in VaultItemCardContent. Keep single bidiTextManager instance at composable scope. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ocal hierarchy Add BidiTextManager to both app and authenticator LocalManagerProvider CompositionLocalProvider blocks. Without this, accessing LocalBidiTextManager.current causes runtime crashes with "CompositionLocal BidiTextManager not present" error. Files modified: - app/.../LocalManagerProvider.kt: Add bidiTextManager parameter and provide - authenticator/.../LocalManagerProvider.kt: Add bidiTextManager parameter and provide This resolves crashes when viewing TOTP verification codes and other bidi-enabled UI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…Content Alphabetically sort BidiTextManager-related imports to follow Kotlin style conventions. No functional changes. Files modified: - VaultItemCardContent.kt: Removed unused LocalBidiTextManager import - VaultItemLoginContent.kt: Reordered LocalBidiTextManager and BidiTextManager imports 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
c316882 to
407f20b
Compare
This commit refactors the `BidiTextManager` to remove the logic for formatting credit card numbers into four-digit chunks. The responsibility for formatting is delegated to the UI components that display the card numbers. The primary objective is to simplify `BidiTextManager`, making it solely responsible for ensuring correct text directionality (LTR/RTL) without handling presentation-layer formatting. This change improves the separation of concerns. Specific changes: - Removed the card number chunking logic from `BidiTextManagerImpl`. The `formatCardNumber` function now only enforces Left-To-Right (LTR) directionality. - Updated `VaultItemCardContent` and `VaultAddEditCardItems` to remove calls to `bidiTextManager.formatCardNumber` and `bidiTextManager.forceLtr`. The values are now passed directly to the composables. - Removed the `BidiTextManager` provider from the `PlatformUiManagerModule` as it's no longer needed as a singleton. - Updated `LocalManagerProvider` in both the `app` and `authenticator` modules to instantiate `BidiTextManager` using the `bidiTextManager()` DSL function. - Removed unnecessary usages of `LocalBidiTextManager` and `forceLtr` for PIN inputs in `BitwardenPinDialog` and `PinInputDialog`. - Adjusted related unit and UI tests to reflect these changes.
|
Claude finished @SaintPatrck's task —— View job Code Review: BidiTextManager for Bidirectional Text HandlingI've completed a comprehensive review of this PR. While the implementation demonstrates good architectural practices, there are critical issues identified by @codokie that need to be addressed before merging. Summary of ChangesThis PR introduces
Critical Issues
|
| Field Type | Method Used | Location |
|---|---|---|
| Password | unicodeWrap() |
VaultItemLoginContent.kt:402 |
| URI | unicodeWrap() |
VaultItemLoginContent.kt:516 |
| Card Number | formatCardNumber() (forceLtr) |
VaultItemCardContent.kt:99 |
| Security Code | forceLtr() |
VaultItemCardContent.kt:179 |
| SSN | forceLtr() |
VaultItemIdentityContent.kt:143 |
unicodeWrap() |
VaultItemIdentityContent.kt:209 | |
| Phone | formatPhoneNumber() (forceLtr) |
VaultItemIdentityContent.kt:231 |
| Passport Number | unicodeWrap() |
VaultItemIdentityContent.kt:165 |
| License Number | unicodeWrap() |
VaultItemIdentityContent.kt:187 |
Questions:
- Why does SSN use
forceLtr()while passport/license numbers useunicodeWrap()? All are typically numeric/alphanumeric identifiers. - Should email addresses always use
unicodeWrap()or should they be forced LTR like phone numbers? - Is there a documented decision matrix for which method to use?
Recommendation: Document the decision criteria for choosing between unicodeWrap(), forceLtr(), and forceRtl() in the interface KDoc or create a separate doc explaining the usage patterns.
4. Verification Code Handling Confirmed Correct ✓
Severity: N/A (Positive Finding)
Per @codokie's confirmation, verification codes correctly display as 123 456 (not 456 123) in RTL mode. Western Arabic numerals are interpreted left-to-right even in RTL contexts. The implementation at VaultItemLoginContent.kt:458-461 and VerificationCodeItem.kt:112 is correct.
Code Quality Issues
5. @OmitFromCoverage Overuse
Severity: Low
Multiple files are marked @OmitFromCoverage without clear justification:
BidiTextManagerImpl.kt:11- Implementation could be unit testedLocalBidiTextManagerProvider.kt:1- CompositionLocal providerBidiTextManagerBuilder.kt:1- DSL builder could be tested
Recommendation: Only use @OmitFromCoverage for truly untestable code (e.g., Android framework dependencies). Consider testing BidiTextManagerImpl with instrumented tests or mock BidiFormatter.
6. Card Number Formatting Removed
Severity: Low (Intentional Change)
Commit 12625daab removed card number formatting logic from formatCardNumber(). The method now only applies forceLtr() without grouping digits.
Before:
override fun formatCardNumber(number: String): String {
val digits = number.filter { it.isDigit() }
val chunks = digits.chunked(4)
return forceLtr(chunks.joinToString(" "))
}After (current):
override fun formatCardNumber(number: String): String {
if (number.isEmpty()) return ""
return forceLtr(number)
}Question: Was this intentional? Does the app handle card number formatting elsewhere?
Recommendation: Confirm this change is intentional and update KDoc if the method no longer provides formatting.
Good Practices Observed 👍
- Clean architecture: Manager pattern in
:uimodule aligns with project structure - Dependency injection: Proper Hilt integration via DSL builder
- CompositionLocal usage: Appropriate for cross-cutting UI concerns
- Interface segregation: Clean interface with focused methods
- Commit hygiene: 21 well-structured commits with clear messages
- Security scan passed: No new vulnerabilities introduced
- Test coverage maintained: 84.78% overall coverage (per Codecov)
Action Items for Author
Must Address (Blocking)
- Add documentation to
BidiTextManagerinterface explaining it should NOT be used with editable TextField components (see Critical Issue Android Accessibility Service #1) - Add comprehensive unit tests for all
BidiTextManagermethods (Issue Site Search #2) - Document decision criteria for when to use
unicodeWrap()vsforceLtr()vsforceRtl()(Issue Fully Implement Change Password Flow for Extension #3)
Should Address (Non-blocking but Important)
- Clarify inconsistent method choices across similar field types (Issue Fully Implement Change Password Flow for Extension #3)
- Confirm card number formatting removal was intentional (Issue F-Droid Support #6)
- Review
@OmitFromCoverageusage and add tests where feasible (Issue Subdomain Only Option for Sites #5)
Nice to Have
- Add instrumented tests showing actual RTL behavior on device/emulator
- Consider adding usage examples to method KDocs
- Document the verification code design decision (123 456 vs 456 123) in code comments
References
- Issue RTL text direction #4753: Original bidirectional text issue
- PR [PM-20026] RTL text direction #5012: Previous attempt (had alignment issues)
- docs/ARCHITECTURE.md - Manager pattern guidelines
- docs/STYLE_AND_BEST_PRACTICES.md - Code style requirements
|
Pivoting to a different approach. |

🎟️ Tracking
PM-25423
📔 Objective
This commit introduces
BidiTextManagerto manage and ensure correct display of text containing both LTR and RTL characters. It includes:BidiTextManagerinterface with aunicodeWrapmethod.BidiTextManagerImplas the default implementation, usingandroidx.core.text.BidiFormatter.LocalBidiTextManagerCompositionLocal for providing the manager in Compose UI.📸 Screenshots
Before
After
⏰ Reminders before review
🦮 Reviewer guidelines
:+1:) or similar for great changes:memo:) or ℹ️ (:information_source:) for notes or general info:question:) for questions:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:) for suggestions / improvements:x:) or:warning:) for more significant problems or concerns needing attention:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt:pick:) for minor or nitpick changes