Compare commits

...

13 Commits

Author SHA1 Message Date
renovate[bot]
2d4412cda8 [deps]: Update gradle minor 2025-12-03 22:01:35 +00:00
David Perez
3bef282426 Update Androidx dependencies to the latest versions (#6224) 2025-12-03 21:25:50 +00:00
Patrick Honkonen
e1bb3a4b5d [PM-27118] Restrict Credential Exchange import based on Personal Ownership policy (#6220) 2025-12-03 20:15:53 +00:00
David Perez
1904c4ffb9 PM-28522: Update the LoginWithDevice ui (#6221) 2025-12-03 19:41:34 +00:00
aj-rosado
26e7178300 [PM-28835] Added validations to prevent duplicate press on buttons (#6209) 2025-12-03 17:46:03 +00:00
David Perez
2c01abda46 [deps]: Update ksp (#6217) 2025-12-02 18:20:51 +00:00
bw-ghapp[bot]
b86cbfcd87 Update SDK to 1.0.0-3958-7f09fd2f (#6213)
Co-authored-by: bw-ghapp[bot] <178206702+bw-ghapp[bot]@users.noreply.github.com>
2025-12-02 14:57:18 +00:00
aj-rosado
3f303d3f39 [BWA-179] Added clarification of functionality on Authenticator's ExportScreen (#6190) 2025-12-02 10:01:00 +00:00
David Perez
ca7a65fc95 PM-28522: Update the Login With Device Screen (#6184) 2025-12-01 16:25:30 +00:00
bw-ghapp[bot]
f02b374e98 Update SDK to 1.0.0-3928-2cca3d46 (#6205)
Co-authored-by: bw-ghapp[bot] <178206702+bw-ghapp[bot]@users.noreply.github.com>
2025-12-01 14:26:56 +00:00
bw-ghapp[bot]
1a90860080 Crowdin Pull (#6206)
Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com>
2025-12-01 14:16:24 +00:00
Patrick Honkonen
adf83cd315 [PM-28157] Revert "Add string extension to prefix URIs with www" (#6192)
Co-authored-by: Álison Fernandes <vvolkgang@users.noreply.github.com>
2025-12-01 14:12:14 +00:00
Patrick Honkonen
489c0ea8d6 Enhance code review skill documentation with TOCs and missing severity categories (#6186)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-27 19:31:25 +00:00
88 changed files with 549 additions and 815 deletions

View File

@@ -1,27 +1,3 @@
Use the `reviewing-changes` skill to review this pull request.
The PR branch is already checked out in the current working directory.
## CRITICAL OUTPUT REQUIREMENTS
**Summary Format (REQUIRED):**
- **Clean PRs (no issues)**: 2-3 lines MAXIMUM
- Format: `**Overall Assessment:** APPROVE\n[One sentence]`
- Example: "Clean refactoring following established patterns"
- **PRs with issues**: Verdict + critical issues list (5-10 lines MAX)
- Format: `**Overall Assessment:** APPROVE/REQUEST CHANGES\n**Critical Issues:**\n- issue 1\nSee inline comments`
- All details go in inline comments with `<details>` tags, NOT in summary
**NEVER create:**
- ❌ Praise sections ("Strengths", "Good Practices", "Excellent X")
- ❌ Verbose analysis sections (Architecture Assessment, Technical Review, Code Quality, etc.)
- ❌ Tables, statistics, or detailed breakdowns in summary
- ❌ Multiple summary sections
- ❌ Checkmarks listing everything done correctly
**Inline Comments:**
- Create separate inline comment for each specific issue/recommendation
- Use collapsible `<details>` sections for code examples and explanations
- Only severity + one-line description visible; all other content collapsed
- Track status of previously identified issues if this is a subsequent review

View File

@@ -1,56 +1,34 @@
---
name: reviewing-changes
version: 2.0.0
description: Comprehensive code reviews for Bitwarden Android. Detects change type (dependency update, bug fix, feature, UI, refactoring, infrastructure) and applies appropriate review depth. Validates MVVM patterns, Hilt DI, security requirements, and test coverage per project standards. Use when reviewing pull requests, checking commits, analyzing code changes, or evaluating architectural compliance.
version: 3.0.0
description: Android-specific code review workflow additions for Bitwarden Android. Provides change type refinements, checklist loading, and reference material organization. Complements bitwarden-code-reviewer agent's base review standards.
---
# Reviewing Changes
# Reviewing Changes - Android Additions
This skill provides Android-specific workflow additions that complement the base `bitwarden-code-reviewer` agent standards.
## Instructions
**IMPORTANT**: Use structured thinking throughout your review process. Plan your analysis in `<thinking>` tags before providing final feedback. This improves accuracy by 40% according to research.
**IMPORTANT**: Use structured thinking throughout your review process. Plan your analysis in `<thinking>` tags before providing final feedback.
### Step 1: Check for Existing Review Threads
Always check for existing comment threads to avoid duplicate comments:
### Step 1: Retrieve Additional Details
<thinking>
Before creating any comments:
1. Is this a fresh review or re-review of the same PR?
2. What existing discussion might already exist?
3. Which findings should update existing threads vs create new?
Determine if more context is available for the changes:
1. Are there JIRA tickets or GitHub Issues mentioned in the PR title or body?
2. Are there other GitHub pull requests mentioned in the PR title or body?
</thinking>
**Thread Detection Procedure:**
Retrieve any additional information linked to the pull request using available tools (JIRA MCP, GitHub API).
1. **Fetch existing comment count:**
```bash
gh pr view <pr-number> --json comments --jq '.comments | length'
```
If pull request title and message do not provide enough context, request additional details from the reviewer:
- Link a JIRA ticket
- Associate a GitHub issue
- Link to another pull request
- Add more detail to the PR title or body
2. **If count = 0:** No existing threads. Skip to Step 2 (all comments will be new).
3. **If count > 0:** Fetch full comment data to check for existing threads.
```bash
gh pr view <pr-number> --json comments --jq '.comments[] | {id, path, line, body}' > pr_comments.json
```
4. **Parse existing threads:** Extract file paths, line numbers, and issue summaries from previous review comments.
- Build map: `{file:line → {comment_id, issue_summary, resolved}}`
- Note which issues already have active discussions
5. **Matching Strategy (Hybrid Approach):**
When you identify an issue to comment on:
- **Exact match:** Same file + same line number → existing thread found
- **Nearby match:** Same file + line within ±5 → existing thread found
- **No match:** Create new inline comment
6. **Handling Evolved Issues:**
- **Issue persists unchanged:** Respond in existing thread with update
- **Issue resolved:** Note resolution in thread response (can mark as resolved if supported)
- **Issue changed significantly:** Resolve/close old thread, create new comment explaining evolution
### Step 2: Detect Change Type
### Step 2: Detect Change Type with Android Refinements
<thinking>
Analyze the changeset systematically:
@@ -60,17 +38,13 @@ Analyze the changeset systematically:
4. What's the risk level of these changes?
</thinking>
Analyze the changeset to determine the primary change type:
Use the base change type detection from the agent, with Android-specific refinements:
**Detection Rules:**
- **Dependency Update**: Only gradle files changed (`libs.versions.toml`, `build.gradle.kts`) with version number modifications
- **Bug Fix**: PR/commit title contains "fix", "bug", or issue ID; addresses existing broken behavior
- **Feature Addition**: New files, new ViewModels, significant new functionality
- **UI Refinement**: Only UI/Compose files changed, layout/styling focus
- **Refactoring**: Code restructuring without behavior change, pattern improvements
- **Infrastructure**: CI/CD files, Gradle config, build scripts, tooling changes
If changeset spans multiple types, use the most complex type's checklist.
**Android-specific patterns:**
- **Feature Addition**: New `ViewModel`, new `Repository`, new `@Composable` functions, new `*Screen.kt` files
- **UI Refinement**: Changes only in `*Screen.kt`, `*Composable.kt`, `ui/` package files
- **Infrastructure**: Changes to `.github/workflows/`, `gradle/`, `build.gradle.kts`, `libs.versions.toml`
- **Dependency Update**: Changes only to `libs.versions.toml` or `build.gradle.kts` with version bumps
### Step 3: Load Appropriate Checklist
@@ -89,7 +63,7 @@ The checklist provides:
- What to check and what to skip
- Structured thinking guidance
### Step 4: Execute Review with Structured Thinking
### Step 4: Execute Review Following Checklist
<thinking>
Before diving into details:
@@ -102,7 +76,7 @@ Before diving into details:
Follow the checklist's multi-pass strategy, thinking through each pass systematically.
### Step 5: Consult Reference Materials As Needed
### Step 5: Consult Android Reference Materials As Needed
Load reference files only when needed for specific questions:
@@ -115,206 +89,10 @@ Load reference files only when needed for specific questions:
- **UI questions** → `reference/ui-patterns.md` (Compose patterns, theming)
- **Style questions** → `docs/STYLE_AND_BEST_PRACTICES.md`
### Step 6: Document Findings
## 🛑 STOP: Determine Output Format FIRST
<thinking>
Before writing ANY output, answer this critical question:
1. Did I find ANY issues (Critical, Important, Suggested, or Questions)?
2. If NO issues found → This is a CLEAN PR → Use 2-3 line minimal format and STOP
3. If issues found → Use verdict + critical issues list + inline comments format
4. NEVER create praise sections or elaborate on correct implementations
</thinking>
**Decision Tree:**
```
Do you have ANY issues to report (Critical/Important/Suggested/Questions)?
├─ NO → CLEAN PR
│ └─ Use 2-3 line format:
│ "**Overall Assessment:** APPROVE
│ [One sentence describing what PR does well]"
│ └─ STOP. Do not proceed to detailed format guidance.
└─ YES → PR WITH ISSUES
└─ Use minimal summary + inline comments:
"**Overall Assessment:** APPROVE / REQUEST CHANGES
**Critical Issues:**
- [issue with file:line]
See inline comments for details."
```
## Special Case: Clean PRs with No Issues
When you find NO critical, important, or suggested issues:
**Minimal Approval Format (REQUIRED):**
```
**Overall Assessment:** APPROVE
[One sentence describing what the PR does well]
```
**Examples:**
- "Clean refactoring following established patterns"
- "Solid bug fix with comprehensive test coverage"
- "Well-structured feature implementation meeting all standards"
**NEVER do this for clean PRs:**
- ❌ Multiple sections (Key Strengths, Changes, Code Quality, etc.)
- ❌ Listing everything that was done correctly
- ❌ Checkmarks for each file or pattern followed
- ❌ Elaborate praise or detailed positive analysis
- ❌ Tables, statistics, or detailed breakdowns
**Why brevity matters:**
- Respects developer time (quick approval = move forward faster)
- Reduces noise in PR conversations
- Saves tokens and processing time
- Focuses attention on PRs that actually need discussion
**If you're tempted to write more than 3 lines for a clean PR, STOP. You're doing it wrong.**
---
<thinking>
Before writing each comment:
1. Is this issue Critical, Important, Suggested, or just Acknowledgment?
2. Should I ask a question or provide direction?
3. What's the rationale I need to explain?
4. What code example would make this actionable?
5. Is there a documentation reference to include?
</thinking>
**CRITICAL**: Use summary comment + inline comments approach.
**Review Comment Structure**:
- Create ONE summary comment with overall verdict + critical issues list
- Create separate inline comment for EACH specific issue on the exact line with full details
- Summary directs readers to inline comments ("See inline comments for details")
- Do NOT duplicate issue details between summary and inline comments
### CRITICAL: No Praise-Only Comments
❌ **NEVER** create inline comments solely for positive feedback
❌ **NEVER** create summary sections like "Strengths", "Good Practices", "What Went Well"
❌ **NEVER** use inline comments to elaborate on correct implementations
Focus exclusively on actionable feedback. Reserve comments for issues requiring attention.
**Inline Comment Format** (REQUIRED: Use `<details>` Tags):
**MUST use `<details>` tags for ALL inline comments.** Only severity + one-line description should be visible; all other content must be collapsed.
```
[emoji] **[SEVERITY]**: [One-line issue description]
<details>
<summary>Details and fix</summary>
[Code example or specific fix]
[Rationale explaining why]
Reference: [docs link if applicable]
</details>
```
**Visibility Rule:**
- **Visible:** Severity prefix (emoji + text) + one-line description
- **Collapsed in `<details>`:** Code examples, rationale, explanations, references
**Example inline comment**:
```
⚠️ **CRITICAL**: Exposes mutable state
<details>
<summary>Details and fix</summary>
Change `MutableStateFlow<State>` to `StateFlow<State>`:
\```kotlin
private val _state = MutableStateFlow<State>()
val state: StateFlow<State> = _state.asStateFlow()
\```
Exposing MutableStateFlow allows external mutation, violating MVVM unidirectional data flow.
Reference: docs/ARCHITECTURE.md#mvvm-pattern
</details>
```
**Summary Comment Format (REQUIRED - No Exceptions):**
When you have issues to report, use this format ONLY:
```
**Overall Assessment:** APPROVE / REQUEST CHANGES
**Critical Issues** (if any):
- [One-line summary with file:line reference]
See inline comments for all details.
```
**Maximum Length**: 5-10 lines total, regardless of PR size or complexity.
**No exceptions for**:
- ❌ Large PRs (10+ files)
- ❌ Multiple issue domains
- ❌ High-severity issues
- ❌ Complex changes
All details belong in inline comments with `<details>` tags, NOT in the summary.
**Output Format Rules**:
**What to Include:**
- **Inline comments**: Create separate comment for EACH specific issue with full details in `<details>` tag
- **Summary comment**: Overall assessment (APPROVE/REQUEST CHANGES) + list of CRITICAL issues only
- **Severity levels** (hybrid emoji + text format):
- ⚠️ **CRITICAL** (blocking)
- 📋 **IMPORTANT** (should fix)
- 💡 **SUGGESTED** (nice to have)
- ❓ **QUESTION** (seeking clarification)
**What to Exclude:**
- **No duplication**: Never repeat inline comment details in the summary
- **No Important/Suggested in summary**: Only CRITICAL blocking issues belong in summary
- **No "Good Practices"/"Strengths" sections**: Never include positive commentary sections
- **No "Action Items" section**: This duplicates inline comments - avoid entirely
- **No verbose analysis**: Keep detailed analysis (compilation status, security review, rollback plans) in inline comments only
### ❌ Common Anti-Patterns to Avoid
**DO NOT:**
- Create multiple summary sections (Strengths, Recommendations, Test Coverage Status, Architecture Compliance)
- Duplicate critical issues in both summary and inline comments
- Write elaborate descriptions in summary (details belong in inline comments)
- Exceed 5-10 lines for simple PRs
- Create inline comments that only provide praise
**DO:**
- Put verdict + critical issue list ONLY in summary
- Put ALL details (explanations, code, rationale) in inline comments with `<details>` collapse
- Keep summary to 5-10 lines maximum, regardless of PR size or your analysis depth
- Focus comments exclusively on actionable issues
**Visibility Guidelines:**
- **Inline comments visible**: Severity + one-line description only
- **Inline comments collapsed**: Code examples, rationale, references in `<details>` tag
- **Summary visible**: Verdict + critical issues list only
See `examples/review-outputs.md` for complete examples.
## Core Principles
- **Minimal reviews for clean PRs**: 2-3 lines when no issues found (see Step 6 format guidance)
- **Issues-focused feedback**: Only comment when there's something actionable; acknowledge good work briefly without elaboration (see priority-framework.md:145-166)
- **Appropriate depth**: Match review rigor to change complexity and risk
- **Specific references**: Always use `file:line_number` format for precise location
- **Actionable feedback**: Say what to do and why, not just what's wrong
- **Constructive tone**: Ask questions for design decisions, explain rationale, focus on code not people
- **Efficient reviews**: Use multi-pass strategy, time-box reviews, skip what's not relevant
- **Efficient reviews**: Use multi-pass strategy, skip what's not relevant
- **Android patterns**: Validate MVVM, Hilt DI, Compose conventions, Kotlin idioms

View File

@@ -2,6 +2,27 @@
Well-structured code reviews demonstrating appropriate depth, tone, and formatting for different change types.
## Table of Contents
**Format Reference:**
- [Quick Format Reference](#quick-format-reference)
- [Inline Comment Format](#inline-comment-format-required)
- [Summary Comment Format](#summary-comment-format)
**Examples:**
- [Example 1: Clean PR (No Issues)](#example-1-clean-pr-no-issues)
- [Example 2: Dependency Update with Breaking Changes](#example-2-dependency-update-with-breaking-changes)
- [Example 3: Feature Addition with Critical Issues](#example-3-feature-addition-with-critical-issues)
**Anti-Patterns:**
- [❌ Anti-Patterns to Avoid](#-anti-patterns-to-avoid)
- [Problem: Verbose Summary with Multiple Sections](#problem-verbose-summary-with-multiple-sections)
- [Problem: Praise-Only Inline Comments](#problem-praise-only-inline-comments)
- [Problem: Missing `<details>` Tags](#problem-missing-details-tags)
**Summary:**
- [Summary](#summary)
---
## Quick Format Reference
@@ -25,10 +46,11 @@ Reference: [docs link if applicable]
```
**Severity Levels:**
- ⚠️ **CRITICAL** - Blocking, must fix
- 📋 **IMPORTANT** - Should fix
- 💡 **SUGGESTED** - Nice to have
- **QUESTION** - Seeking clarification
- **CRITICAL** - Blocking, must fix (security, crashes, architecture violations)
- ⚠️ **IMPORTANT** - Should fix (missing tests, quality issues)
- ♻️ **DEBT** - Technical debt (duplication, convention violations, future rework needed)
- 🎨 **SUGGESTED** - Nice to have (refactoring, improvements)
- 💭 **QUESTION** - Seeking clarification (requirements, design decisions)
### Summary Comment Format
@@ -81,7 +103,7 @@ See inline comments for migration details.
**Inline Comment 1** (on `network/api/BitwardenApiService.kt:34`):
```markdown
⚠️ **CRITICAL**: API migration required for Retrofit 3.0
**CRITICAL**: API migration required for Retrofit 3.0
<details>
<summary>Details and fix</summary>
@@ -136,7 +158,7 @@ See inline comments for all issues and suggestions.
**Inline Comment 1** (on `app/vault/unlock/UnlockViewModel.kt:78`):
```markdown
⚠️ **CRITICAL**: Exposes mutable state
**CRITICAL**: Exposes mutable state
<details>
<summary>Details and fix</summary>
@@ -160,7 +182,7 @@ Reference: docs/ARCHITECTURE.md#mvvm-pattern
**Inline Comment 2** (on `data/vault/UnlockRepository.kt:145`):
```markdown
⚠️ **CRITICAL**: PIN stored without encryption - SECURITY ISSUE
**CRITICAL**: PIN stored without encryption - SECURITY ISSUE
<details>
<summary>Details and fix</summary>
@@ -188,7 +210,7 @@ Reference: docs/ARCHITECTURE.md#security
**Inline Comment 3** (on `app/vault/unlock/UnlockViewModel.kt:92`):
```markdown
📋 **IMPORTANT**: Missing error handling test
⚠️ **IMPORTANT**: Missing error handling test
<details>
<summary>Details and fix</summary>
@@ -214,7 +236,7 @@ Ensures error flow remains robust across refactorings.
**Inline Comment 4** (on `app/vault/unlock/UnlockViewModel.kt:105`):
```markdown
💡 **SUGGESTED**: Consider rate limiting for PIN attempts
🎨 **SUGGESTED**: Consider rate limiting for PIN attempts
<details>
<summary>Details and fix</summary>
@@ -246,7 +268,7 @@ Would add security layer against brute force. Consider discussing threat model w
**Inline Comment 5** (on `app/vault/unlock/UnlockScreen.kt:134`):
```markdown
**QUESTION**: Can we use BitwardenTextField?
💭 **QUESTION**: Can we use BitwardenTextField?
<details>
<summary>Details</summary>
@@ -356,7 +378,7 @@ This is exactly the right approach for fail-safe security.
**What NOT to do:**
```markdown
⚠️ **CRITICAL**: Missing test coverage for security-critical code
**CRITICAL**: Missing test coverage for security-critical code
The `@OmitFromCoverage` annotation excludes this entire class from test coverage.
@@ -382,7 +404,7 @@ Security-critical code should have the highest test coverage, not be omitted.
**Correct approach:**
```markdown
⚠️ **CRITICAL**: Missing test coverage for security-critical code
**CRITICAL**: Missing test coverage for security-critical code
<details>
<summary>Details and fix</summary>
@@ -422,5 +444,3 @@ Security-critical code should have the highest test coverage, not be omitted.
- Praise-only inline comments
- Duplication between summary and inline comments
- Verbose analysis in summary (belongs in inline comments)
See `SKILL.md` for complete review guidelines.

View File

@@ -2,6 +2,22 @@
Quick reference for Bitwarden Android architectural patterns during code reviews. For comprehensive details, read `docs/ARCHITECTURE.md` and `docs/STYLE_AND_BEST_PRACTICES.md`.
## Table of Contents
**Core Patterns:**
- [MVVM + UDF Pattern](#mvvm--udf-pattern)
- [ViewModel Structure](#viewmodel-structure)
- [UI Layer (Compose)](#ui-layer-compose)
- [Hilt Dependency Injection](#hilt-dependency-injection)
- [ViewModels](#viewmodels)
- [Repositories and Managers](#repositories-and-managers)
- [Module Organization](#module-organization)
- [Error Handling](#error-handling)
- [Use Result Types, Not Exceptions](#use-result-types-not-exceptions)
- [Quick Checklist](#quick-checklist)
---
## MVVM + UDF Pattern
### ViewModel Structure

View File

@@ -1,8 +1,28 @@
# Issue Priority Framework
# Finding Priority Framework
Use this framework to classify findings during code review. Clear prioritization helps authors triage and address issues effectively.
## Critical (Blocker - Must Fix Before Merge)
## Table of Contents
**Severity Categories:**
- [❌ CRITICAL (Blocker - Must Fix Before Merge)](#critical-blocker---must-fix-before-merge)
- [⚠️ IMPORTANT (Should Fix)](#important-should-fix)
- [♻️ DEBT (Technical Debt)](#debt-technical-debt)
- [🎨 SUGGESTED (Nice to Have)](#suggested-nice-to-have)
- [💭 QUESTION (Seeking Clarification)](#question-seeking-clarification)
- [Optional (Acknowledge But Don't Require)](#optional-acknowledge-but-dont-require)
**Guidelines:**
- [Classification Guidelines](#classification-guidelines)
- [When Something is Between Categories](#when-something-is-between-categories)
- [Context Matters](#context-matters)
- [Examples by Change Type](#examples-by-change-type)
- [Special Cases](#special-cases)
- [Summary](#summary)
---
## ❌ **CRITICAL** (Blocker - Must Fix Before Merge)
These issues **must** be addressed before the PR can be merged. They pose immediate risks to security, stability, or architecture integrity.
@@ -49,7 +69,7 @@ This violates MVVM encapsulation pattern.
---
## Important (Should Fix)
## ⚠️ **IMPORTANT** (Should Fix)
These issues should be addressed but don't block merge if there's a compelling reason. They improve code quality, maintainability, or robustness.
@@ -102,7 +122,53 @@ Fetching items one-by-one in loop. Consider batch fetch to reduce database queri
---
## Suggested (Nice to Have)
## ♻️ **DEBT** (Technical Debt)
Code that duplicates existing patterns, violates established conventions, or will require rework within 6 months. Introduces technical debt that should be tracked for future cleanup.
### Duplication
- Copy-pasted code blocks across files
- Repeated validation or business logic
- Multiple implementations of same pattern
- Data transformation duplicated in multiple places
**Example**:
```
**app/vault/VaultListViewModel.kt:156** - DEBT: Duplicates encryption logic
Same encryption pattern exists in VaultRepository.kt:234 and SyncManager.kt:89.
Extract to shared EncryptionUtil to reduce maintenance burden.
```
### Convention Violations
- Inconsistent error handling approaches within same module
- Mixing architectural patterns (MVVM + MVC)
- Not following established DI patterns
- Deviating from project code style significantly
**Example**:
```
**data/auth/AuthRepository.kt:78** - DEBT: Exception-based error handling
Project standard is Result<T> for error handling. This uses try-catch with throws.
Creates inconsistency and makes testing harder.
Reference: docs/ARCHITECTURE.md#error-handling
```
### Future Rework Required
- Hardcoded values that should be configurable
- Temporary workarounds without TODO/FIXME
- Code that will need changes when planned features arrive
- Tight coupling that prevents future extensibility
**Example**:
```
**app/settings/SettingsViewModel.kt:45** - DEBT: Hardcoded feature flags
Feature flags should come from remote config for A/B testing.
Will require rework when experimentation framework launches.
```
---
## 🎨 **SUGGESTED** (Nice to Have)
These are improvement opportunities but not required. Consider the effort vs. benefit before requesting changes.
@@ -142,6 +208,80 @@ Could be extracted to separate validator class for reusability and testing.
---
## 💭 **QUESTION** (Seeking Clarification)
Questions about requirements, unclear intent, or potential conflicts that require human knowledge to answer. Open inquiries that cannot be resolved through code inspection alone.
### Requirements Clarification
- Ambiguous acceptance criteria
- Multiple valid implementation approaches
- Unclear business rules or edge case handling
- Conflicting requirements between specs and implementation
**Example**:
```
**app/vault/ItemListViewModel.kt:67** - QUESTION: Expected sort behavior for equal timestamps?
When items have identical timestamps, should secondary sort be by:
- Name (alphabetical)
- Creation order
- Item type priority
Spec doesn't specify tie-breaking logic.
```
### Design Decisions
- Architecture choices that could go multiple ways
- Trade-offs between approaches without clear winner
- Feature flag strategy or rollout approach
- API design with multiple valid patterns
**Example**:
```
**data/sync/SyncManager.kt:134** - QUESTION: Should sync failures retry automatically?
Current implementation fails immediately. Options:
- Exponential backoff (3 retries)
- User-triggered retry only
- Background retry on network restore
What's the expected UX?
```
### System Integration
- Unclear contracts with external systems
- Potential conflicts with other features/modules
- Assumptions about third-party API behavior
- Cross-team coordination needs
**Example**:
```
**app/auth/BiometricPrompt.kt:89** - QUESTION: Compatibility with pending device credentials PR?
PR #1234 is refactoring device credentials. Should this:
- Merge first and adapt later
- Wait for #1234 to land
- Coordinate with that author
Timing unclear.
```
### Testing Strategy
- Uncertainty about test scope or approach
- Questions about mocking external dependencies
- Edge cases that need product input
- Performance testing requirements
**Example**:
```
**data/vault/EncryptionTest.kt:45** - QUESTION: Should we test against real Keystore?
Currently using mocked Keystore. Real Keystore testing would:
+ Catch hardware-specific issues
- Slow down CI significantly
- Require API 23+ emulators
What's the priority?
```
---
## Optional (Acknowledge But Don't Require)
Note good practices to reinforce positive patterns. Keep these **brief** - list only, no elaboration.
@@ -175,11 +315,26 @@ Note good practices to reinforce positive patterns. Keep these **brief** - list
- If yes → Critical
- If no → Important
**If unsure between Important and Debt**:
- Ask: "Is this a bug/defect or just duplication/inconsistency?"
- If bug/defect → Important
- If duplication/inconsistency → Debt
**If unsure between Important and Suggested**:
- Ask: "Would I block merge over this?"
- If yes → Important
- If no → Suggested
**If unsure between Debt and Suggested**:
- Ask: "Will this require rework within 6 months?"
- If yes → Debt
- If no → Suggested
**If unsure between Suggested and Question**:
- Ask: "Am I requesting a change or asking for clarification?"
- If requesting change → Suggested
- If seeking clarification → Question
**If unsure between Suggested and Optional**:
- Ask: "Is this actionable feedback or just acknowledgment?"
- If actionable → Suggested
@@ -270,5 +425,7 @@ Missing tests for refactored helper → SUGGESTED
**Critical**: Block merge, must fix (security, stability, architecture)
**Important**: Should fix before merge (testing, quality, performance)
**Debt**: Technical debt introduced, track for future cleanup
**Suggested**: Nice to have, consider effort vs benefit
**Question**: Seeking clarification on requirements or design
**Optional**: Acknowledge good practices, keep brief

View File

@@ -2,6 +2,20 @@
Effective code review feedback is clear, actionable, and constructive. This guide provides phrasing patterns for inline comments.
## Table of Contents
**Guidelines:**
- [Core Directives](#core-directives)
- [Phrasing Templates](#phrasing-templates)
- [Critical Issues (Prescriptive)](#critical-issues-prescriptive)
- [Suggested Improvements (Exploratory)](#suggested-improvements-exploratory)
- [Questions (Collaborative)](#questions-collaborative)
- [Test Suggestions](#test-suggestions)
- [When to Be Prescriptive vs Ask Questions](#when-to-be-prescriptive-vs-ask-questions)
- [Special Cases](#special-cases)
---
## Core Directives
- **Keep positive feedback minimal**: For clean PRs with no issues, use 2-3 line approval only. When acknowledging good practices in PRs with issues, use single bullet list with no elaboration. Never create elaborate sections praising correct implementations.

View File

@@ -3,7 +3,6 @@ package com.x8bit.bitwarden.data.credentials.manager
import androidx.credentials.provider.CallingAppInfo
import com.bitwarden.network.service.DigitalAssetLinkService
import com.bitwarden.ui.platform.base.util.prefixHttpsIfNecessary
import com.bitwarden.ui.platform.base.util.prefixWwwIfNecessary
import com.x8bit.bitwarden.data.credentials.model.ValidateOriginResult
import com.x8bit.bitwarden.data.credentials.repository.PrivilegedAppRepository
import com.x8bit.bitwarden.data.platform.manager.AssetManager
@@ -41,13 +40,7 @@ class OriginManagerImpl(
): ValidateOriginResult {
return digitalAssetLinkService
.checkDigitalAssetLinksRelations(
sourceWebSite = relyingPartyId
// The DAL API does not allow redirects, so we add `www.` to prevent redirects
// when it is absent from the `relyingPartyId`. This ensures that relying
// parties storing their `assetlinks.json` at the `www.` subdomain do not fail
// verification checks.
.prefixWwwIfNecessary()
.prefixHttpsIfNecessary(),
sourceWebSite = relyingPartyId.prefixHttpsIfNecessary(),
targetPackageName = callingAppInfo.packageName,
targetCertificateFingerprint = callingAppInfo
.getSignatureFingerprintAsHexString()

View File

@@ -1,16 +1,11 @@
package com.x8bit.bitwarden.ui.auth.feature.loginwithdevice
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -20,7 +15,6 @@ import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.testTag
@@ -30,17 +24,21 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitwarden.ui.platform.base.util.EventsEffect
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
import com.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
import com.bitwarden.ui.platform.components.button.BitwardenOutlinedButton
import com.bitwarden.ui.platform.components.card.BitwardenContentCard
import com.bitwarden.ui.platform.components.content.BitwardenLoadingContent
import com.bitwarden.ui.platform.components.content.model.ContentBlockData
import com.bitwarden.ui.platform.components.dialog.BitwardenBasicDialog
import com.bitwarden.ui.platform.components.dialog.BitwardenLoadingDialog
import com.bitwarden.ui.platform.components.indicator.BitwardenCircularProgressIndicator
import com.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
import com.bitwarden.ui.platform.components.text.BitwardenClickableText
import com.bitwarden.ui.platform.components.text.BitwardenHyperTextLink
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
import kotlinx.collections.immutable.persistentListOf
/**
* The top level composable for the Login with Device screen.
@@ -120,111 +118,99 @@ private fun LoginWithDeviceScreenContent(
modifier = modifier
.verticalScroll(rememberScrollState()),
) {
Spacer(modifier = Modifier.height(height = 24.dp))
Text(
text = state.title(),
textAlign = TextAlign.Start,
style = BitwardenTheme.typography.headlineMedium,
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.titleMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.padding(horizontal = 16.dp)
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(24.dp))
Spacer(modifier = Modifier.height(height = 12.dp))
Text(
text = state.subtitle(),
textAlign = TextAlign.Start,
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.padding(horizontal = 16.dp)
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(16.dp))
Spacer(modifier = Modifier.height(height = 12.dp))
Text(
text = state.description(),
textAlign = TextAlign.Start,
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
modifier = Modifier
.padding(horizontal = 16.dp)
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = stringResource(id = BitwardenString.fingerprint_phrase),
textAlign = TextAlign.Start,
style = BitwardenTheme.typography.titleLarge,
color = BitwardenTheme.colorScheme.text.primary,
BitwardenContentCard(
contentItems = persistentListOf(
ContentBlockData(
headerText = stringResource(id = BitwardenString.fingerprint_phrase),
subtitleText = state.fingerprintPhrase,
),
),
contentHeaderTextStyle = BitwardenTheme.typography.titleMedium,
contentSubtitleTextStyle = BitwardenTheme.typography.sensitiveInfoSmall,
contentSubtitleColor = BitwardenTheme.colorScheme.text.codePink,
modifier = Modifier
.padding(horizontal = 16.dp)
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(12.dp))
Text(
text = state.fingerprintPhrase,
textAlign = TextAlign.Start,
color = BitwardenTheme.colorScheme.text.codePink,
style = BitwardenTheme.typography.sensitiveInfoSmall,
minLines = 2,
modifier = Modifier
.testTag("FingerprintPhraseValue")
.padding(horizontal = 16.dp)
.testTag(tag = "FingerprintPhraseValue")
.standardHorizontalMargin()
.fillMaxWidth(),
)
if (state.allowsResend) {
Column(
verticalArrangement = Arrangement.Center,
Spacer(modifier = Modifier.height(height = 24.dp))
BitwardenOutlinedButton(
label = stringResource(id = BitwardenString.resend_notification),
onClick = onResendNotificationClick,
modifier = Modifier
.defaultMinSize(minHeight = 40.dp)
.align(Alignment.Start),
) {
if (state.isResendNotificationLoading) {
BitwardenCircularProgressIndicator(
modifier = Modifier
.padding(horizontal = 64.dp)
.size(size = 16.dp),
)
} else {
BitwardenClickableText(
modifier = Modifier.testTag("ResendNotificationButton"),
label = stringResource(id = BitwardenString.resend_notification),
style = BitwardenTheme.typography.labelLarge,
innerPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
onClick = onResendNotificationClick,
)
}
}
.testTag(tag = "ResendNotificationButton")
.standardHorizontalMargin()
.fillMaxWidth(),
)
}
Spacer(modifier = Modifier.height(28.dp))
Spacer(modifier = Modifier.height(height = 24.dp))
Text(
text = state.otherOptions(),
textAlign = TextAlign.Start,
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
textAlign = TextAlign.Center,
style = BitwardenTheme.typography.bodySmall,
color = BitwardenTheme.colorScheme.text.secondary,
modifier = Modifier
.padding(horizontal = 16.dp)
.standardHorizontalMargin()
.fillMaxWidth(),
)
BitwardenClickableText(
modifier = Modifier.testTag("ViewAllLoginOptionsButton"),
label = stringResource(id = BitwardenString.view_all_login_options),
innerPadding = PaddingValues(vertical = 8.dp, horizontal = 16.dp),
style = BitwardenTheme.typography.labelLarge,
Spacer(modifier = Modifier.height(height = 12.dp))
BitwardenHyperTextLink(
annotatedResId = BitwardenString.need_another_option_view_all_login_options,
annotationKey = "viewAll",
accessibilityString = stringResource(id = BitwardenString.view_all_login_options),
onClick = onViewAllLogInOptionsClick,
style = BitwardenTheme.typography.bodySmall,
modifier = Modifier
.testTag(tag = "ViewAllLoginOptionsButton")
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(height = 12.dp))
Spacer(modifier = Modifier.navigationBarsPadding())
}
}

View File

@@ -52,7 +52,7 @@ class LoginWithDeviceViewModel @Inject constructor(
private var authJob: Job = Job().apply { complete() }
init {
sendNewAuthRequest(isResend = false)
sendNewAuthRequest()
}
override fun handleAction(action: LoginWithDeviceAction) {
@@ -74,7 +74,14 @@ class LoginWithDeviceViewModel @Inject constructor(
}
private fun handleResendNotificationClicked() {
sendNewAuthRequest(isResend = true)
mutableStateFlow.update {
it.copy(
dialogState = LoginWithDeviceState.DialogState.Loading(
message = BitwardenString.resending.asText(),
),
)
}
sendNewAuthRequest()
}
private fun handleViewAllLogInOptionsClicked() {
@@ -99,9 +106,6 @@ class LoginWithDeviceViewModel @Inject constructor(
) {
when (val result = action.result) {
is CreateAuthRequestResult.Success -> {
updateContent { content ->
content.copy(isResendNotificationLoading = false)
}
mutableStateFlow.update {
it.copy(
dialogState = null,
@@ -123,7 +127,6 @@ class LoginWithDeviceViewModel @Inject constructor(
viewState = LoginWithDeviceState.ViewState.Content(
loginWithDeviceType = it.loginWithDeviceType,
fingerprintPhrase = result.authRequest.fingerprint,
isResendNotificationLoading = false,
),
dialogState = null,
)
@@ -131,9 +134,6 @@ class LoginWithDeviceViewModel @Inject constructor(
}
is CreateAuthRequestResult.Error -> {
updateContent { content ->
content.copy(isResendNotificationLoading = false)
}
mutableStateFlow.update {
it.copy(
dialogState = LoginWithDeviceState.DialogState.Error(
@@ -149,9 +149,6 @@ class LoginWithDeviceViewModel @Inject constructor(
CreateAuthRequestResult.Declined -> Unit
CreateAuthRequestResult.Expired -> {
updateContent { content ->
content.copy(isResendNotificationLoading = false)
}
mutableStateFlow.update {
it.copy(
dialogState = LoginWithDeviceState.DialogState.Error(
@@ -279,8 +276,7 @@ class LoginWithDeviceViewModel @Inject constructor(
}
}
private fun sendNewAuthRequest(isResend: Boolean) {
setIsResendNotificationLoading(isResend)
private fun sendNewAuthRequest() {
authJob.cancel()
authJob = authRepository
.createAuthRequestWithUpdates(
@@ -291,22 +287,6 @@ class LoginWithDeviceViewModel @Inject constructor(
.onEach(::sendAction)
.launchIn(viewModelScope)
}
private fun setIsResendNotificationLoading(isResend: Boolean) {
updateContent { it.copy(isResendNotificationLoading = isResend) }
}
private inline fun updateContent(
crossinline block: (
LoginWithDeviceState.ViewState.Content,
) -> LoginWithDeviceState.ViewState.Content?,
) {
val currentViewState = state.viewState
val updatedContent = (currentViewState as? LoginWithDeviceState.ViewState.Content)
?.let(block)
?: return
mutableStateFlow.update { it.copy(viewState = updatedContent) }
}
}
/**
@@ -349,13 +329,10 @@ data class LoginWithDeviceState(
* Content state for the [LoginWithDeviceScreen] showing the actual content or items.
*
* @property fingerprintPhrase The fingerprint phrase to present to the user.
* @property isResendNotificationLoading Indicates if the resend loading spinner should be
* displayed.
*/
@Parcelize
data class Content(
val fingerprintPhrase: String,
val isResendNotificationLoading: Boolean,
private val loginWithDeviceType: LoginWithDeviceType,
) : ViewState() {
/**
@@ -401,14 +378,19 @@ data class LoginWithDeviceState(
/**
* The text to display indicating that there are other option for logging in.
*/
@Suppress("MaxLineLength")
val otherOptions: Text
get() = when (loginWithDeviceType) {
LoginWithDeviceType.OTHER_DEVICE,
LoginWithDeviceType.SSO_OTHER_DEVICE,
-> BitwardenString.log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app_need_another_option.asText()
-> {
BitwardenString
.log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app
.asText()
}
LoginWithDeviceType.SSO_ADMIN_APPROVAL -> BitwardenString.trouble_logging_in.asText()
LoginWithDeviceType.SSO_ADMIN_APPROVAL -> {
BitwardenString.trouble_logging_in.asText()
}
}
/**

View File

@@ -2,14 +2,17 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.vault
import androidx.lifecycle.viewModelScope
import com.bitwarden.core.data.manager.model.FlagKey
import com.bitwarden.network.model.PolicyTypeJson
import com.bitwarden.ui.platform.base.BackgroundEvent
import com.bitwarden.ui.platform.base.BaseViewModel
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
import com.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.ui.platform.model.SnackbarRelay
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -25,6 +28,7 @@ class VaultSettingsViewModel @Inject constructor(
snackbarRelayManager: SnackbarRelayManager<SnackbarRelay>,
private val firstTimeActionManager: FirstTimeActionManager,
private val featureFlagManager: FeatureFlagManager,
private val policyManager: PolicyManager,
) : BaseViewModel<VaultSettingsState, VaultSettingsEvent, VaultSettingsAction>(
initialState = run {
val firstTimeState = firstTimeActionManager.currentOrDefaultUserFirstTimeState
@@ -55,7 +59,13 @@ class VaultSettingsViewModel @Inject constructor(
featureFlagManager
.getFeatureFlagFlow(key = FlagKey.CredentialExchangeProtocolImport)
.map { VaultSettingsAction.Internal.ImportFeatureUpdated(it) }
.combine(
policyManager.getActivePoliciesFlow(type = PolicyTypeJson.PERSONAL_OWNERSHIP),
) { isEnabled, policies ->
VaultSettingsAction.Internal.CredentialExchangeAvailabilityChanged(
isEnabled = isEnabled && policies.isEmpty(),
)
}
.onEach(::sendAction)
.launchIn(viewModelScope)
}
@@ -80,8 +90,8 @@ class VaultSettingsViewModel @Inject constructor(
handleSnackbarDataReceived(action)
}
is VaultSettingsAction.Internal.ImportFeatureUpdated -> {
handleImportFeatureUpdated(action)
is VaultSettingsAction.Internal.CredentialExchangeAvailabilityChanged -> {
handleCredentialExchangeAvailabilityChanged(action)
}
}
}
@@ -92,8 +102,8 @@ class VaultSettingsViewModel @Inject constructor(
sendEvent(VaultSettingsEvent.ShowSnackbar(action.data))
}
private fun handleImportFeatureUpdated(
action: VaultSettingsAction.Internal.ImportFeatureUpdated,
private fun handleCredentialExchangeAvailabilityChanged(
action: VaultSettingsAction.Internal.CredentialExchangeAvailabilityChanged,
) {
mutableStateFlow.update { it.copy(showImportItemsChevron = action.isEnabled) }
}
@@ -128,7 +138,9 @@ class VaultSettingsViewModel @Inject constructor(
}
private fun handleImportItemsClicked() {
if (featureFlagManager.getFeatureFlag(FlagKey.CredentialExchangeProtocolImport)) {
if (featureFlagManager.getFeatureFlag(FlagKey.CredentialExchangeProtocolImport) &&
policyManager.getActivePolicies(PolicyTypeJson.PERSONAL_OWNERSHIP).isEmpty()
) {
sendEvent(VaultSettingsEvent.NavigateToImportItems)
} else {
sendEvent(VaultSettingsEvent.NavigateToImportVault)
@@ -218,9 +230,9 @@ sealed class VaultSettingsAction {
*/
sealed class Internal : VaultSettingsAction() {
/**
* Indicates that the import feature flag has been updated.
* Indicates that the CXF import feature availability has changed.
*/
data class ImportFeatureUpdated(
data class CredentialExchangeAvailabilityChanged(
val isEnabled: Boolean,
) : Internal()

View File

@@ -242,64 +242,6 @@ class OriginManagerTest {
),
)
}
@Test
fun `validateOrigin should prefix www to rpId without www before checking asset links`() =
runTest {
coEvery {
mockDigitalAssetLinkService.checkDigitalAssetLinksRelations(
sourceWebSite = "https://www.example.com",
targetPackageName = DEFAULT_PACKAGE_NAME,
targetCertificateFingerprint = DEFAULT_CERT_FINGERPRINT,
relations = listOf("delegate_permission/common.handle_all_urls"),
)
} returns DEFAULT_ASSET_LINKS_CHECK_RESPONSE.asSuccess()
val result = originManager.validateOrigin(
relyingPartyId = "example.com",
callingAppInfo = mockNonPrivilegedAppInfo,
)
assertEquals(ValidateOriginResult.Success(null), result)
}
@Test
fun `validateOrigin should preserve existing www prefix when present`() = runTest {
coEvery {
mockDigitalAssetLinkService.checkDigitalAssetLinksRelations(
sourceWebSite = "https://www.example.com",
targetPackageName = DEFAULT_PACKAGE_NAME,
targetCertificateFingerprint = DEFAULT_CERT_FINGERPRINT,
relations = listOf("delegate_permission/common.handle_all_urls"),
)
} returns DEFAULT_ASSET_LINKS_CHECK_RESPONSE.asSuccess()
val result = originManager.validateOrigin(
relyingPartyId = "www.example.com",
callingAppInfo = mockNonPrivilegedAppInfo,
)
assertEquals(ValidateOriginResult.Success(null), result)
}
@Test
fun `validateOrigin should handle rpId with https scheme correctly`() = runTest {
coEvery {
mockDigitalAssetLinkService.checkDigitalAssetLinksRelations(
sourceWebSite = "https://www.example.com",
targetPackageName = DEFAULT_PACKAGE_NAME,
targetCertificateFingerprint = DEFAULT_CERT_FINGERPRINT,
relations = listOf("delegate_permission/common.handle_all_urls"),
)
} returns DEFAULT_ASSET_LINKS_CHECK_RESPONSE.asSuccess()
val result = originManager.validateOrigin(
relyingPartyId = "https://example.com",
callingAppInfo = mockNonPrivilegedAppInfo,
)
assertEquals(ValidateOriginResult.Success(null), result)
}
}
private const val DEFAULT_PACKAGE_NAME = "com.x8bit.bitwarden"

View File

@@ -7,6 +7,7 @@ import androidx.compose.ui.test.isDialog
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performFirstLinkClick
import androidx.compose.ui.test.performScrollTo
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.ui.platform.manager.IntentManager
@@ -92,7 +93,10 @@ class LoginWithDeviceScreenTest : BitwardenComposeTest() {
@Test
fun `view all log in options click should send ViewAllLogInOptionsClick action`() {
composeTestRule.onNodeWithText("View all log in options").performScrollTo().performClick()
composeTestRule
.onNodeWithText(text = "Need another option? View all login options")
.performScrollTo()
.performFirstLinkClick()
verify {
viewModel.trySendAction(LoginWithDeviceAction.ViewAllLogInOptionsClick)
}
@@ -168,7 +172,6 @@ private val DEFAULT_STATE = LoginWithDeviceState(
emailAddress = EMAIL,
viewState = LoginWithDeviceState.ViewState.Content(
fingerprintPhrase = "alabster-drinkable-mystified-rapping-irrigate",
isResendNotificationLoading = false,
loginWithDeviceType = LoginWithDeviceType.OTHER_DEVICE,
),
dialogState = null,

View File

@@ -121,8 +121,8 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
viewModel.trySendAction(LoginWithDeviceAction.ResendNotificationClick)
assertEquals(
DEFAULT_STATE.copy(
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
isResendNotificationLoading = true,
dialogState = LoginWithDeviceState.DialogState.Loading(
message = BitwardenString.resending.asText(),
),
),
viewModel.stateFlow.value,
@@ -610,7 +610,6 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
DEFAULT_STATE.copy(
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
fingerprintPhrase = FINGERPRINT,
isResendNotificationLoading = false,
),
dialogState = LoginWithDeviceState.DialogState.Error(
title = BitwardenString.an_error_has_occurred.asText(),
@@ -661,7 +660,6 @@ class LoginWithDeviceViewModelTest : BaseViewModelTest() {
DEFAULT_STATE.copy(
viewState = DEFAULT_CONTENT_VIEW_STATE.copy(
fingerprintPhrase = FINGERPRINT,
isResendNotificationLoading = false,
),
dialogState = LoginWithDeviceState.DialogState.Error(
title = null,
@@ -693,7 +691,6 @@ private const val FINGERPRINT = "fingerprint"
private val DEFAULT_CONTENT_VIEW_STATE = LoginWithDeviceState.ViewState.Content(
fingerprintPhrase = FINGERPRINT,
isResendNotificationLoading = false,
loginWithDeviceType = LoginWithDeviceType.OTHER_DEVICE,
)

View File

@@ -3,12 +3,15 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.vault
import app.cash.turbine.test
import com.bitwarden.core.data.manager.model.FlagKey
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.network.model.PolicyTypeJson
import com.bitwarden.network.model.SyncResponseJson
import com.bitwarden.ui.platform.base.BaseViewModelTest
import com.bitwarden.ui.platform.components.snackbar.model.BitwardenSnackbarData
import com.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
import com.bitwarden.ui.util.asText
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
import com.x8bit.bitwarden.ui.platform.model.SnackbarRelay
import io.mockk.every
@@ -38,6 +41,11 @@ class VaultSettingsViewModelTest : BaseViewModelTest() {
getFeatureFlagFlow(FlagKey.CredentialExchangeProtocolImport)
} returns mutableFeatureFlagFlow
}
private val mutablePoliciesFlow = bufferedMutableSharedFlow<List<SyncResponseJson.Policy>>()
private val policyManager = mockk<PolicyManager> {
every { getActivePolicies(any()) } returns emptyList()
every { getActivePoliciesFlow(any()) } returns mutablePoliciesFlow
}
private val mutableSnackbarSharedFlow = bufferedMutableSharedFlow<BitwardenSnackbarData>()
private val snackbarRelayManager = mockk<SnackbarRelayManager<SnackbarRelay>> {
@@ -84,6 +92,25 @@ class VaultSettingsViewModelTest : BaseViewModelTest() {
}
}
@Test
fun `ImportItemsClick should emit NavigateToImportVault when policy is not empty`() = runTest {
every {
featureFlagManager.getFeatureFlag(FlagKey.CredentialExchangeProtocolImport)
} returns true
every {
policyManager.getActivePolicies(PolicyTypeJson.PERSONAL_OWNERSHIP)
} returns listOf(mockk())
val viewModel = createViewModel()
viewModel.eventFlow.test {
viewModel.trySendAction(VaultSettingsAction.ImportItemsClick)
assertEquals(
VaultSettingsEvent.NavigateToImportVault,
awaitItem(),
)
}
}
@Suppress("MaxLineLength")
@Test
fun `ImportItemsClick should emit NavigateToImportItems when CredentialExchangeProtocolImport is enabled`() =
@@ -160,21 +187,36 @@ class VaultSettingsViewModelTest : BaseViewModelTest() {
}
@Test
fun `CredentialExchangeProtocolImport flag changes should update state accordingly`() {
fun `showImportItemsChevron should display based on feature flag and policies`() {
val viewModel = createViewModel()
// Verify chevron is shown when feature flag is enabled and no policies (default state)
assertEquals(
viewModel.stateFlow.value,
VaultSettingsState(showImportActionCard = true, showImportItemsChevron = true),
)
// Verify chevron is hidden when feature flag is disabled and no policies
mutableFeatureFlagFlow.tryEmit(false)
mutablePoliciesFlow.tryEmit(emptyList())
assertEquals(
viewModel.stateFlow.value,
VaultSettingsState(showImportActionCard = true, showImportItemsChevron = false),
)
// Verify chevron is hidden when feature flag is enabled and policies exist
mutableFeatureFlagFlow.tryEmit(true)
mutablePoliciesFlow.tryEmit(listOf(mockk()))
assertEquals(
viewModel.stateFlow.value,
VaultSettingsState(showImportActionCard = true, showImportItemsChevron = true),
VaultSettingsState(showImportActionCard = true, showImportItemsChevron = false),
)
// Verify chevron is hidden when feature flag is disabled and no policies
mutableFeatureFlagFlow.tryEmit(false)
mutablePoliciesFlow.tryEmit(emptyList())
assertEquals(
viewModel.stateFlow.value,
VaultSettingsState(showImportActionCard = true, showImportItemsChevron = false),
)
}
@@ -182,6 +224,7 @@ class VaultSettingsViewModelTest : BaseViewModelTest() {
firstTimeActionManager = firstTimeActionManager,
snackbarRelayManager = snackbarRelayManager,
featureFlagManager = featureFlagManager,
policyManager = policyManager,
)
}

View File

@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
@@ -23,6 +24,7 @@ import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -45,6 +47,7 @@ import com.bitwarden.ui.platform.composition.LocalIntentManager
import com.bitwarden.ui.platform.manager.IntentManager
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.resource.BitwardenString
import com.bitwarden.ui.platform.theme.BitwardenTheme
import kotlinx.collections.immutable.toImmutableList
/**
@@ -175,7 +178,34 @@ private fun ExportScreenContent(
.verticalScroll(rememberScrollState()),
) {
val resources = LocalResources.current
Spacer(modifier = Modifier.height(height = 24.dp))
Text(
text = stringResource(id = BitwardenString.included_in_this_export),
style = BitwardenTheme.typography.titleMedium,
color = BitwardenTheme.colorScheme.text.primary,
textAlign = TextAlign.Center,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(height = 12.dp))
Text(
text = stringResource(
id = BitwardenString.only_codes_stored_locally_on_this_device_will_be_exported,
),
style = BitwardenTheme.typography.bodyMedium,
color = BitwardenTheme.colorScheme.text.primary,
textAlign = TextAlign.Center,
modifier = Modifier
.standardHorizontalMargin()
.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(height = 24.dp))
BitwardenMultiSelectButton(
label = stringResource(id = BitwardenString.file_format),
options = ExportVaultFormat.entries.map { it.displayLabel() }.toImmutableList(),

View File

@@ -13,30 +13,30 @@ minSdkBwa = "28"
# Dependency Versions
androidGradlePlugin = "8.13.1"
androidxActivity = "1.11.0"
androidxActivity = "1.12.1"
androidxAppCompat = "1.7.1"
androdixAutofill = "1.3.0"
androidxBiometrics = "1.2.0-alpha05"
androidxBrowser = "1.9.0"
androidxCamera = "1.5.1"
androidxComposeBom = "2025.10.01"
androidxComposeBom = "2025.12.00"
androidxCore = "1.17.0"
androidxCredentials = "1.6.0-beta03"
androidxCredentialsProviderEvents = "1.0.0-alpha03"
androidxHiltNavigationCompose = "1.3.0"
androidxLifecycle = "2.9.4"
androidxLifecycle = "2.10.0"
androidxNavigation = "2.9.6"
androidxRoom = "2.8.3"
androidxRoom = "2.8.4"
androidxSecurityCrypto = "1.1.0"
androidxSplash = "1.2.0"
androidxWork = "2.11.0"
bitwardenSdk = "1.0.0-3908-4b0d1280"
bitwardenSdk = "1.0.0-3958-7f09fd2f"
crashlytics = "3.0.6"
detekt = "1.23.8"
firebaseBom = "34.5.0"
firebaseBom = "34.6.0"
glide = "1.0.0-beta01"
googleGuava = "33.5.0-jre"
googleProtoBufJava = "4.33.0"
googleProtoBufJava = "4.33.1"
googleProtoBufPlugin = "0.9.5"
googleServices = "4.4.4"
googleReview = "2.0.2"
@@ -48,16 +48,16 @@ kotlinxCollectionsImmutable = "0.4.0"
kotlinxCoroutines = "1.10.2"
kotlinxSerialization = "1.9.0"
kotlinxKover = "0.9.3"
ksp = "2.3.0"
ksp = "2.3.3"
mockk = "1.14.6"
okhttp = "5.3.0"
okhttp = "5.3.2"
retrofitBom = "3.0.0"
robolectric = "4.16"
sonarqube = "7.0.1.6134"
sonarqube = "7.1.0.6387"
testng = "7.11.0"
timber = "5.0.1"
turbine = "1.2.1"
zxing = "3.5.3"
zxing = "3.5.4"
[libraries]
# Format: <maintainer>-<artifact-name>

View File

@@ -239,34 +239,6 @@ fun String.prefixHttpsIfNecessaryOrNull(): String? =
fun String.prefixHttpsIfNecessary(): String =
prefixHttpsIfNecessaryOrNull() ?: this
/**
* If the given [String] is a valid URI, "www." will be prepended (or inserted after the scheme
* if present) if it is not already present. Otherwise `null` will be returned.
*
* Examples:
* - "example.com" -> "www.example.com"
* - "www.example.com" -> "www.example.com"
* - "https://example.com" -> "https://www.example.com"
* - "https://www.example.com" -> "https://www.example.com"
*/
fun String.prefixWwwIfNecessaryOrNull(): String? =
when {
this.isBlank() || !this.isValidUri() -> null
this.startsWith("www.") -> this
this.startsWith("http://") || this.startsWith("https://") -> {
if ("://www." in this) this else this.replaceFirst("://", "://www.")
}
else -> "www.$this"
}
/**
* If the given [String] is a valid URI, "www." will be prepended (or inserted after the scheme
* if present) if it is not already present. Otherwise the original [String] will be returned.
*/
fun String.prefixWwwIfNecessary(): String =
prefixWwwIfNecessaryOrNull() ?: this
/**
* Checks if a string is using base32 digits.
*/

View File

@@ -18,6 +18,7 @@ import com.bitwarden.ui.platform.base.util.cardStyle
import com.bitwarden.ui.platform.components.button.color.bitwardenFilledButtonColors
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.bitwarden.ui.platform.components.util.throttledClick
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.theme.BitwardenTheme
@@ -48,7 +49,7 @@ fun BitwardenFilledButton(
modifier = modifier
.semantics(mergeDescendants = true) {}
.cardStyle(cardStyle = cardStyle, padding = cardInsets),
onClick = onClick,
onClick = throttledClick(onClick = onClick),
enabled = isEnabled,
contentPadding = PaddingValues(
top = 10.dp,

View File

@@ -19,6 +19,7 @@ import com.bitwarden.ui.platform.components.button.color.bitwardenOutlinedButton
import com.bitwarden.ui.platform.components.button.model.BitwardenOutlinedButtonColors
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.components.util.rememberVectorPainter
import com.bitwarden.ui.platform.components.util.throttledClick
import com.bitwarden.ui.platform.resource.BitwardenDrawable
import com.bitwarden.ui.platform.theme.BitwardenTheme
@@ -50,7 +51,7 @@ fun BitwardenOutlinedButton(
modifier = modifier
.semantics(mergeDescendants = true) { }
.cardStyle(cardStyle = cardStyle, padding = cardInsets),
onClick = onClick,
onClick = throttledClick(onClick = onClick),
enabled = isEnabled,
contentPadding = PaddingValues(
top = 10.dp,

View File

@@ -15,6 +15,7 @@ import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.bitwarden.ui.platform.components.button.color.bitwardenTextButtonColors
import com.bitwarden.ui.platform.components.util.throttledClick
import com.bitwarden.ui.platform.theme.BitwardenTheme
/**
@@ -37,7 +38,7 @@ fun BitwardenTextButton(
) {
TextButton(
modifier = modifier.semantics(mergeDescendants = true) {},
onClick = onClick,
onClick = throttledClick(onClick = onClick),
enabled = isEnabled,
contentPadding = PaddingValues(
top = 10.dp,

View File

@@ -1,15 +1,15 @@
package com.bitwarden.ui.platform.components.card
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import com.bitwarden.ui.platform.base.util.cardBackground
import com.bitwarden.ui.platform.components.content.BitwardenContentBlock
import com.bitwarden.ui.platform.components.content.model.ContentBlockData
import com.bitwarden.ui.platform.components.model.CardStyle
import com.bitwarden.ui.platform.theme.BitwardenTheme
import kotlinx.collections.immutable.ImmutableList
@@ -20,6 +20,7 @@ import kotlinx.collections.immutable.ImmutableList
* @param contentItems list of [ContentBlockData] items to display.
* @param contentHeaderTextStyle the text style to use for the header text of the content.
* @param contentSubtitleTextStyle the text style to use for the subtitle text of the content.
* @param contentSubtitleColor the color that should be applied to subtitle text of the content.
* @param contentBackgroundColor the background color to use for the content.
*/
@Composable
@@ -28,13 +29,13 @@ fun BitwardenContentCard(
modifier: Modifier = Modifier,
contentHeaderTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
contentSubtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
contentSubtitleColor: Color = BitwardenTheme.colorScheme.text.secondary,
contentBackgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
) {
Column(
modifier = modifier
.fillMaxWidth()
.clip(shape = BitwardenTheme.shapes.content)
.background(color = BitwardenTheme.colorScheme.background.secondary),
.cardBackground(cardStyle = CardStyle.Full, color = contentBackgroundColor),
) {
contentItems.forEachIndexed { index, item ->
BitwardenContentBlock(
@@ -42,6 +43,7 @@ fun BitwardenContentCard(
showDivider = index != contentItems.lastIndex,
headerTextStyle = contentHeaderTextStyle,
subtitleTextStyle = contentSubtitleTextStyle,
subtitleColor = contentSubtitleColor,
backgroundColor = contentBackgroundColor,
)
}

View File

@@ -35,6 +35,7 @@ fun BitwardenContentBlock(
modifier: Modifier = Modifier,
headerTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
subtitleColor: Color = BitwardenTheme.colorScheme.text.secondary,
backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
showDivider: Boolean = true,
) {
@@ -44,6 +45,7 @@ fun BitwardenContentBlock(
headerTextStyle = headerTextStyle,
subtitleText = data.subtitleText,
subtitleTextStyle = subtitleTextStyle,
subtitleColor = subtitleColor,
iconVectorResource = data.iconVectorResource,
backgroundColor = backgroundColor,
showDivider = showDivider,
@@ -61,6 +63,7 @@ private fun BitwardenContentBlock(
headerTextStyle: TextStyle = BitwardenTheme.typography.titleSmall,
subtitleText: AnnotatedString? = null,
subtitleTextStyle: TextStyle = BitwardenTheme.typography.bodyMedium,
subtitleColor: Color = BitwardenTheme.colorScheme.text.secondary,
showDivider: Boolean = true,
@DrawableRes iconVectorResource: Int? = null,
backgroundColor: Color = BitwardenTheme.colorScheme.background.secondary,
@@ -102,7 +105,7 @@ private fun BitwardenContentBlock(
Text(
text = it,
style = subtitleTextStyle,
color = BitwardenTheme.colorScheme.text.secondary,
color = subtitleColor,
)
}
Spacer(Modifier.height(12.dp))

View File

@@ -37,6 +37,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalFocusManager
@@ -94,6 +95,7 @@ import kotlinx.collections.immutable.toImmutableList
* @param readOnly `true` if the input should be read-only and not accept user interactions.
* @param enabled Whether or not the text field is enabled.
* @param textStyle An optional style that may be used to override the default used.
* @param textColor An optional color that may be used to override the text color.
* @param shouldAddCustomLineBreaks If `true`, line breaks will be inserted to allow for filling
* an entire line before breaking. `false` by default.
* @param visualTransformation Transforms the visual representation of the input [value].
@@ -123,6 +125,7 @@ fun BitwardenTextField(
readOnly: Boolean = false,
enabled: Boolean = true,
textStyle: TextStyle = BitwardenTheme.typography.bodyLarge,
textColor: Color = BitwardenTheme.colorScheme.text.primary,
shouldAddCustomLineBreaks: Boolean = false,
keyboardType: KeyboardType = KeyboardType.Text,
keyboardActions: KeyboardActions = KeyboardActions.Default,
@@ -158,6 +161,7 @@ fun BitwardenTextField(
readOnly = readOnly,
enabled = enabled,
textStyle = textStyle,
textColor = textColor,
shouldAddCustomLineBreaks = shouldAddCustomLineBreaks,
keyboardType = keyboardType,
keyboardActions = keyboardActions,
@@ -194,6 +198,7 @@ fun BitwardenTextField(
* @param readOnly `true` if the input should be read-only and not accept user interactions.
* @param enabled Whether or not the text field is enabled.
* @param textStyle An optional style that may be used to override the default used.
* @param textColor An optional color that may be used to override the text color.
* @param shouldAddCustomLineBreaks If `true`, line breaks will be inserted to allow for filling
* an entire line before breaking. `false` by default.
* @param visualTransformation Transforms the visual representation of the input [value].
@@ -226,6 +231,7 @@ fun BitwardenTextField(
readOnly: Boolean = false,
enabled: Boolean = true,
textStyle: TextStyle = BitwardenTheme.typography.bodyLarge,
textColor: Color = BitwardenTheme.colorScheme.text.primary,
shouldAddCustomLineBreaks: Boolean = false,
keyboardType: KeyboardType = KeyboardType.Text,
keyboardActions: KeyboardActions = KeyboardActions.Default,
@@ -312,7 +318,7 @@ fun BitwardenTextField(
var focused by remember { mutableStateOf(false) }
TextField(
colors = bitwardenTextFieldColors(),
colors = bitwardenTextFieldColors(textColor = textColor),
enabled = enabled,
label = label?.let {
{

View File

@@ -24,6 +24,7 @@ fun bitwardenTextFieldButtonColors(): TextFieldColors = bitwardenTextFieldColors
*/
@Composable
fun bitwardenTextFieldColors(
textColor: Color = BitwardenTheme.colorScheme.text.primary,
disabledTextColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
disabledLeadingIconColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
disabledTrailingIconColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
@@ -31,8 +32,8 @@ fun bitwardenTextFieldColors(
disabledPlaceholderColor: Color = BitwardenTheme.colorScheme.text.secondary,
disabledSupportingTextColor: Color = BitwardenTheme.colorScheme.filledButton.foregroundDisabled,
): TextFieldColors = TextFieldColors(
focusedTextColor = BitwardenTheme.colorScheme.text.primary,
unfocusedTextColor = BitwardenTheme.colorScheme.text.primary,
focusedTextColor = textColor,
unfocusedTextColor = textColor,
disabledTextColor = disabledTextColor,
errorTextColor = BitwardenTheme.colorScheme.text.primary,
focusedContainerColor = Color.Transparent,

View File

@@ -0,0 +1,38 @@
package com.bitwarden.ui.platform.components.util
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
/**
* Creates a throttled click handler that prevents rapid successive clicks.
*
* @param coroutineScope The coroutine scope for launching click handlers.
* @param delayMs The minimum time in milliseconds between clicks.
* @param onClick The action to perform when clicked.
* @return A throttled click handler function.
*/
@Composable
fun throttledClick(
coroutineScope: CoroutineScope = rememberCoroutineScope(),
delayMs: Long = 300,
onClick: () -> Unit,
): () -> Unit {
var isEnabled by remember { mutableStateOf(value = true) }
return {
coroutineScope.launch {
if (isEnabled) {
isEnabled = false
onClick()
delay(timeMillis = delayMs)
isEnabled = true
}
}
}
}

View File

@@ -1156,7 +1156,4 @@ Wil u na die rekening omskakel?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1188,7 +1188,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1157,7 +1157,4 @@ fəaliyyəti yaxalamaq üçün sizə vaxt verəcək.</string>
<string name="lock_app">Tətbiqi kilidlə</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Tətbiqin kilidini açmaq üçün cihazın kilid üsulunu istifadə edin</string>
<string name="loading_vault_data">Seyf veriləri yüklənir…</string>
<string name="compatibility_mode_warning">Uyumluluq rejimi, yalnız brauzerinizdə avto-doldurma işləməsə fəallaşdırılmalıdır. Bu ayar, təhlükəsizliyi azaldır və zərərli saytların parollarınızı ələ keçirməsinə imkan verə bilər. Yalnız bu riski qəbul etdiyiniz təqdirdə fəallaşdırın.</string>
<string name="use_compatibility_mode_for_browser_autofill">Brauzerdə avto-doldurma üçün uyumluluq rejimini istifadə et</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Daha çox brauzerlə uyumlu olarkən daha az güvənli avto-doldurma üsulunu istifadə edir.\n<annotation link="learnMore">Uyumluluq rejimi barədə daha ətraflı</annotation></string>
</resources>

View File

@@ -1171,7 +1171,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -691,7 +691,7 @@
<string name="follow_the_steps_from_duo_to_finish_logging_in">Следвайте стъпките от Duo, за да завършите вписването.</string>
<string name="launch_duo">Стартиране на Duo</string>
<string name="your_passkey_will_be_saved_to_your_bitwarden_vault_for_x">Секретният ключ ще бъде запазен в трезора на Битуорден за %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Your password will be saved to your Bitwarden vault for %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Паролата ще бъде запазена в трезора на Битуорден за %1$s</string>
<string name="passkeys_not_supported_for_this_app">За това приложение не се поддържат секретни ключове</string>
<string name="passkey_operation_failed_because_browser_is_not_privileged">Операцията със секретния ключ беше неуспешна, тъй като потребителят не може да бъде потвърден.</string>
<string name="passkey_operation_failed_because_browser_signature_does_not_match">Операцията със секретния ключ беше неуспешна, тъй като подписът в браузъра не съвпада</string>
@@ -918,8 +918,8 @@
<string name="passkey_operation_failed_because_the_request_is_unsupported">Операцията със секретния ключ беше неуспешна, тъй като заявката не се поддържа.</string>
<string name="password_operation_failed_because_the_selected_item_does_not_exist">Операцията с паролата беше неуспешна, тъй като избраният елемент не съществува.</string>
<string name="password_operation_failed_because_no_item_was_selected">Операцията с паролата беше неуспешна, тъй като няма избран елемент.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Credential operation failed because the request is invalid.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Credential operation failed because the request is unsupported.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Операцията с данни за вписване беше неуспешна, тъй като заявката е грешна.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Операцията с данни за вписване беше неуспешна, тъй като заявката не се поддържа.</string>
<string name="credential_operation_failed_because_user_verification_attempts_exceeded">Операцията с удостоверителните данни беше неуспешна, тъй като е превишен броят на опитите за потвърждение на потребителя.</string>
<string name="credential_operation_failed_because_user_is_locked_out">Операцията с удостоверителните данни беше неуспешна, тъй като потребителят е заключен извън системата.</string>
<string name="credential_operation_failed_because_the_selected_item_does_not_exist">Операцията с удостоверителните данни беше неуспешна, тъй като избраният елемент не съществува.</string>
@@ -1158,7 +1158,4 @@
<string name="lock_app">Заключване на приложението</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Използвайте начина на заключване на устройството за отключване на приложението</string>
<string name="loading_vault_data">Зареждане на данните от трезора…</string>
<string name="compatibility_mode_warning">Режимът на съвместимост трябва да е включен само, ако автоматичното попълване не работи във Вашия браузър. Тази настройка намалява нивото на сигурност и може да позволи на злонамерените уеб сайтове да прихванат паролите Ви. Включете я само, ако приемате този риск.</string>
<string name="use_compatibility_mode_for_browser_autofill">Използване на режима на съвместимост за авт. попълване в браузъра</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Използва по-несигурен начин за автоматично попълване, което е съвместимо с повече браузъри.\n<annotation link="learnMore">Научете повече относно режима на съвместимост</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1163,7 +1163,4 @@ Skeniranje će biti izvršeno automatski.</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Voleu canviar a aquest compte?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1173,7 +1173,4 @@ při opakování problémů.</string>
<string name="lock_app">Uzamknout aplikaci</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Použít metodu uzamčení zařízení k odemknutí aplikace</string>
<string name="loading_vault_data">Načítání dat trezoru...</string>
<string name="compatibility_mode_warning">Režim kompatibility by měl být povolen jen v případě, že automatické vyplňování nefunguje ve Vašem prohlížeči. Toto nastavení snižuje bezpečnost a umožňuje zachytávání Vašich hesel škodlivým webům. Povolte jen pokud toto riziko přijmete.</string>
<string name="use_compatibility_mode_for_browser_autofill">Použít režim kompatibility pro automatické vyplňování prohlížeče</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Používá méně bezpečnou metodu automatického vyplňování, která je kompatibilní s více prohlížeči.\n<annotation link="learnMore">Další informace o režimu kompatibility</annotation></string>
</resources>

View File

@@ -1188,7 +1188,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Skift til denne konto?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1155,7 +1155,4 @@ Möchtest du zu diesem Konto wechseln?</string>
<string name="lock_app">App sperren</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Nutze die Sperrmethode deines Geräts, um die App zu entsperren</string>
<string name="loading_vault_data">Tresor-Daten werden geladen…</string>
<string name="compatibility_mode_warning">Der Kompatibilitätsmodus sollte nur aktiviert werden, wenn Auto-Ausfüllen in deinem Browser nicht funktioniert. Diese Einstellung verringert die Sicherheit und könnte es bösartigen Websites erlauben, deine Passwörter zu erfassen. Aktiviere sie nur, wenn du dieses Risiko akzeptierst.</string>
<string name="use_compatibility_mode_for_browser_autofill">Kompatibilitätsmodus für Browser-Auto-Ausfüllen verwenden</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Verwende eine weniger sicher Auto-Ausfüllen-Methode, die mit weiteren Browsern kompatibel ist.\n<annotation link="learnMore">Erfahre mehr über den Kompatibilitätsmodus</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1158,7 +1158,4 @@ any issues.</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1158,7 +1158,4 @@ any issues.</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1157,7 +1157,4 @@ seleccione Agregar TOTP para almacenar la clave de forma segura</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Soovid selle konto peale lülituda?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1154,7 +1154,4 @@ Kontu honetara aldatu nahi duzu?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Haluatko vaihtaa tähän tiliin?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Gusto mo bang pumunta sa account na ito?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -691,7 +691,7 @@ Voulez-vous basculer vers ce compte ?</string>
<string name="follow_the_steps_from_duo_to_finish_logging_in">Suivez les étapes à partir de Duo pour terminer la connexion.</string>
<string name="launch_duo">Lancer Duo</string>
<string name="your_passkey_will_be_saved_to_your_bitwarden_vault_for_x">Votre clé d\'accès sera enregistrée votre coffre Bitwarden pour %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Your password will be saved to your Bitwarden vault for %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Votre mot de passe sera enregistré dans votre coffre Bitwarden pour %1$s</string>
<string name="passkeys_not_supported_for_this_app">Clés d\'accès non supportées par cette application</string>
<string name="passkey_operation_failed_because_browser_is_not_privileged">L\'opération Passkey a échoué car le navigateur n\'est pas privilégié</string>
<string name="passkey_operation_failed_because_browser_signature_does_not_match">L\'opération de clé de passe a échoué car la signature du navigateur ne correspond pas</string>
@@ -918,8 +918,8 @@ Voulez-vous basculer vers ce compte ?</string>
<string name="passkey_operation_failed_because_the_request_is_unsupported">L\'opération de clé de passe a échoué car la demande n\'est pas prise en charge.</string>
<string name="password_operation_failed_because_the_selected_item_does_not_exist">L\'opération de mot de passe a échoué car l\'élément sélectionné n\'existe pas.</string>
<string name="password_operation_failed_because_no_item_was_selected">L\'opération de mot de passe a échoué car aucun élément n\'a été sélectionné.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Credential operation failed because the request is invalid.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Credential operation failed because the request is unsupported.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Opération d\'identification échouée car la requête n\'est pas valide.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Opération d\'identification échouée car la requête n\'est pas prise en charge.</string>
<string name="credential_operation_failed_because_user_verification_attempts_exceeded">L\'opération d\'identification a échoué car les tentatives de vérification de l\'utilisateur ont été dépassées.</string>
<string name="credential_operation_failed_because_user_is_locked_out">L\'opération d\'identification a échoué car l\'utilisateur est bloqué.</string>
<string name="credential_operation_failed_because_the_selected_item_does_not_exist">L\'opération d\'identification a échoué car l\'élément sélectionné n\'existe pas.</string>
@@ -1156,7 +1156,4 @@ Voulez-vous basculer vers ce compte ?</string>
<string name="lock_app">Verrouiller l\'application</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Utilisez la méthode de verrouillage de votre appareil pour déverrouiller l\'application</string>
<string name="loading_vault_data">Chargement des données du coffre…</string>
<string name="compatibility_mode_warning">Le mode de compatibilité ne devrait être activé que si le remplissage automatique ne fonctionne pas dans votre navigateur. Ce paramètre réduit la sécurité et peut permettre à des sites malveillants de saisir vos mots de passe. Ne l\'activez que si vous acceptez ce risque.</string>
<string name="use_compatibility_mode_for_browser_autofill">Utiliser le mode de compatibilité pour la saisie automatique du navigateur</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Utilise une méthode de saisie automatique moins sécurisée compatible avec plus de navigateurs.\n<annotation link="learnMore">En savoir plus sur le mode de compatibilité</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Queres comprobalo dende esa conta?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1155,7 +1155,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -693,7 +693,7 @@
<string name="follow_the_steps_from_duo_to_finish_logging_in">Pratite Duo korake za dovršetak prijave.</string>
<string name="launch_duo">Pokreni Duo</string>
<string name="your_passkey_will_be_saved_to_your_bitwarden_vault_for_x">Tvoj pristupni ključ za %1$s će biti spremljen u trezor</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Your password will be saved to your Bitwarden vault for %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Tvoja će lozinka biti spremljena u tvoj Bitwatden trezor za %1$s</string>
<string name="passkeys_not_supported_for_this_app">Pristupni ključ nije podržan za ovu aplikaciju</string>
<string name="passkey_operation_failed_because_browser_is_not_privileged">Operacija lozinke nije uspjela jer preglednik nema privilegiju</string>
<string name="passkey_operation_failed_because_browser_signature_does_not_match">Operacija pristupnog ključa nije uspjela jer se potpis preglednika ne podudara</string>
@@ -922,8 +922,8 @@
<string name="passkey_operation_failed_because_the_request_is_unsupported">Operacija s pristupnim ključem nije uspjela jer zahtjev nije podržan.</string>
<string name="password_operation_failed_because_the_selected_item_does_not_exist">Operacija lozinke nije uspjela jer odabrana stavka ne postoji.</string>
<string name="password_operation_failed_because_no_item_was_selected">Operacija lozinke nije uspjela jer nije odabrana niti jedna stavka.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Credential operation failed because the request is invalid.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Credential operation failed because the request is unsupported.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Operacija vjerodajnice nije uspjela jer zahtjev nije valjan.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Operacija vjerodajnice nije uspjela jer zahtjev nije podržan.</string>
<string name="credential_operation_failed_because_user_verification_attempts_exceeded">Operacije vjerodajnice nije uspjela jer je premašen broj provjere korisnika.</string>
<string name="credential_operation_failed_because_user_is_locked_out">Operacija vjerodajnice nije uspjela jer je korisnik zaključan.</string>
<string name="credential_operation_failed_because_the_selected_item_does_not_exist">Operacija vjerodajnice nije uspjela jer ne postoji odabrana stavka.</string>
@@ -1164,7 +1164,4 @@ bilo kakav problem.</string>
<string name="lock_app">Zaključaj aplikaciju</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Upotrijebi metodu zaključavanja uređaja za otključavanje aplikacije</string>
<string name="loading_vault_data">Učitavanje podataka trezora…</string>
<string name="compatibility_mode_warning">Način kompatibilnosti treba omogućiti samo ako automatsko popunjavanje ne radi u tvojem pregledniku. Ova postavka smanjuje sigurnost i mogla bi omogućiti zlonamjernim stranicama da snime tvoje lozinke. Omogući samo ako prihvaćaš taj rizik.</string>
<string name="use_compatibility_mode_for_browser_autofill">Koristi način kompatibilnosti za auto-ispunu preglednika</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Koristi manje sigurnu metodu auto-ispune kompatibilnu s više preglednika.\n<annotation link="learnMore">Saznaj više o načinu kompatibilnosti</annotation></string>
</resources>

View File

@@ -1155,7 +1155,4 @@ Szeretnénk átváltani erre a fiókra?</string>
<string name="lock_app">Alkalmazás zárolása</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Az alkalmazás feloldásához használjuk a készülék zárolási módszerét.</string>
<string name="loading_vault_data">Széf adatok betöltése…</string>
<string name="compatibility_mode_warning">A kompatibilitási módot csak akkor szabad engedélyezni, ha az automatikus kitöltés nem működik a böngészőben. Ez a beállítás csökkenti a biztonságot és lehetővé teheti a rosszindulatú webhelyek számára a jelszavak rögzítését. Csak akkor engedélyezzük, ha elfogadjuk ezt a kockázatot.</string>
<string name="use_compatibility_mode_for_browser_autofill">A kompatibilitási mód használata a böngésző automatikus kitöltéséhez.</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Kevésbé biztonságos, több böngészővel kompatibilis automatikus kitöltési módszert használunk.\n<annotation link="learnMore">Tudjunk meg többet a kompatibilitási módról</annotation></string>
</resources>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about">Tentang</string>
<string name="add_folder">Tambah Folder</string>
<string name="add_folder">Tambah folder</string>
<string name="add_item">Tambah Item</string>
<string name="an_error_has_occurred">Terjadi kesalahan</string>
<string name="apply">Terapkan</string>
@@ -1148,7 +1148,4 @@ Apakah Anda ingin beralih ke akun ini?</string>
<string name="lock_app">Kunci aplikasi</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Gunakan metode kunci perangkat Anda untuk membuka kunci aplikasi</string>
<string name="loading_vault_data">Memuat data brangkas…</string>
<string name="compatibility_mode_warning">Mode kompatibilitas hanya boleh diaktifkan jika pengisian otomatis tidak berfungsi di peramban Anda. Pengaturan ini mengurangi keamanan dan dapat memungkinkan situs jahat untuk menangkap sandi Anda. Hanya aktifkan jika Anda menerima risiko ini.</string>
<string name="use_compatibility_mode_for_browser_autofill">Gunakan mode kompatibilitas untuk pengisian otomatis peramban</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Gunakan metode pengisian otomatis kurang aman yang kompatibel dengan lebih banyak peramban.\n<annotation link="learnMore">Pelajari lebih lanjut tentang mode kompatibilitas</annotation></string>
</resources>

View File

@@ -136,7 +136,7 @@
<string name="other">Altro</string>
<string name="password_generator">Generatore di password</string>
<string name="password_hint">Suggerimento per la password</string>
<string name="password_hint_alert">Weve sent you an email with your master password hint.</string>
<string name="password_hint_alert">Ti abbiamo inviato un\'email con il suggerimento per la tua password principale.</string>
<string name="password_override_alert">Vuoi davvero sovrascrivere questa password?</string>
<string name="retype_master_password">Conferma della password principale</string>
<string name="retype_new_master_password_required">Conferma della nuova password (necessaria)</string>
@@ -179,7 +179,7 @@
<string name="send_verification_code_again">Invia un nuovo codice di verifica</string>
<string name="verification_email_not_sent">Invio dell\'email di verifica non riuscito</string>
<string name="verification_email_sent">Email di verifica inviata</string>
<string name="yubi_key_instruction">To continue, hold your Yubico security key against the back of the device or insert it into your devices USB port, then touch its button.</string>
<string name="yubi_key_instruction">Appoggia la YubiKey NEO sul retro del dispositivo o inserisci la Yubikey nella porta USB e premi il pulsante dedicato.</string>
<string name="yubi_key_title">Chiave di sicurezza YubiKey</string>
<string name="add_new_attachment">Aggiungi un allegato</string>
<string name="attachments">File allegati</string>
@@ -341,7 +341,7 @@
<string name="generator">Generatore</string>
<string name="no_folders_to_list">Nessuna cartella</string>
<string name="fingerprint_phrase">Frase impronta</string>
<string name="your_accounts_fingerprint">Your accounts fingerprint phrase</string>
<string name="your_accounts_fingerprint">Frase di verifica dell\'account</string>
<string name="export_vault">Esporta la cassaforte</string>
<string name="lock_now">Blocca</string>
<string name="pin">Codice PIN</string>
@@ -375,7 +375,7 @@
<string name="download">Scarica</string>
<string name="login_expired">Sessione scaduta</string>
<string name="biometrics_direction">Autenticazione biometrica</string>
<string name="device_verification">Device verification</string>
<string name="device_verification">Verifica del dispositivo</string>
<string name="biometrics_failed">Autenticazione biometrica fallita</string>
<string name="biometrics_decoding_failure">Effettua l\'accesso con la password principale o il codice PIN. Puoi riabilitare l\'autenticazione biometrica nelle impostazioni.</string>
<string name="use_biometrics_to_unlock">Sblocca con dati biometrici</string>
@@ -388,7 +388,7 @@
<string name="export_vault_file_pw_protect_info">Questa esportazione contiene i dati della cassaforte in un formato crittografato. Sarà necessario inserire la password del file per decrittografarlo.</string>
<string name="export_vault_confirmation_title">Esporta la cassaforte</string>
<string name="warning">Avviso</string>
<string name="export_vault_failure">There was a problem exporting your vault. If the problem persists, youll need to export from the web vault.</string>
<string name="export_vault_failure">Esportazione della cassaforte non riuscita. Prova a ripetere l\'operazione da Bitwarden Web.</string>
<string name="export_vault_success">Cassaforte esportata</string>
<string name="clone">Copia</string>
<string name="password_generator_policy_in_effect">Il generatore di password è limitato dalle politiche dell\'organizzazione</string>
@@ -409,7 +409,7 @@
<string name="enable_sync_on_refresh">Gesto di sincronizzazione</string>
<string name="enable_sync_on_refresh_description">Sincronizza la cassaforte quando scorri verso il basso.</string>
<string name="log_in_sso">Single Sign-On aziendale</string>
<string name="log_in_sso_summary">Quickly log in using your organizations single sign-on portal. Please enter your organizations identifier to begin.</string>
<string name="log_in_sso_summary">Effettua l\'accesso in modo più comodo, veloce e centralizzato con l\'SSO della tua organizzazione. Inserisci il tuo identificativo per iniziare.</string>
<string name="org_identifier">Identificativo dell\'organizzazione</string>
<string name="login_sso_error">Accesso con SSO non riuscito</string>
<string name="set_master_password">Imposta la password principale</string>
@@ -478,7 +478,7 @@
<string name="seven_days">7 giorni</string>
<string name="thirty_days">30 giorni</string>
<string name="custom">Personalizzata</string>
<string name="custom_timeout">Custom timeout</string>
<string name="custom_timeout">Timeout personalizzato</string>
<string name="add_this_authenticator_key_to_a_login">Aggiungi questa chiave di autenticazione a un login esistente o crea un nuovo login</string>
<string name="send_disabled_warning">L\'eliminazione dei Send è limitata dall\'organizzazione a solo i Send esistenti</string>
<string name="about_send">Scopri di più sui Send</string>
@@ -500,18 +500,18 @@ Tutte le sessioni attive verranno terminate entro un\'ora.</string>
<string name="reset_password_auto_enroll_invite_warning">Questa organizzazione ha una politica che consente agli amministratori dell\'organizzazione di cambiare la tua password principale</string>
<string name="hours_minutes_format" comment="Used to display a number of hours and minutes">%1$s, %2$s</string>
<plurals name="hours_format" comment="Can be injected into a sentence with %1$s and %2$s">
<item quantity="one">%1$d hour</item>
<item quantity="other">%1$d hours</item>
<item quantity="one">%1$d ora</item>
<item quantity="other">%1$d ore</item>
</plurals>
<plurals name="minutes_format" comment="Can be injected into a sentence with %1$s and %2$s">
<item quantity="one">%1$d minute</item>
<item quantity="other">%1$d minutes</item>
<item quantity="one">%1$d minuto</item>
<item quantity="other">%1$d minuti</item>
</plurals>
<string name="vault_timeout_policy_in_effect_hours_minutes_format" comment="First value will be the number of hours (2 hours, 1 hour) and second value will be the number of minutes (15 minutes, 1 minute)">Your organization has set the maximum session timeout to %1$s and %2$s.</string>
<string name="vault_timeout_policy_in_effect_format" comment="Value will be a number of hours or minutes (15 minutes, or 1 minute)">Your organization has set the maximum session timeout to %1$s.</string>
<string name="this_setting_is_managed_by_your_organization">This setting is managed by your organization.</string>
<string name="your_organization_has_set_the_default_session_timeout_to_never">Your organization has set the default session timeout to never.</string>
<string name="your_organization_has_set_the_default_session_timeout_to_on_app_restart">Your organization has set the default session timeout to on app restart.</string>
<string name="vault_timeout_policy_in_effect_hours_minutes_format" comment="First value will be the number of hours (2 hours, 1 hour) and second value will be the number of minutes (15 minutes, 1 minute)">La tua organizzazione ha impostato %1$s e %2$s come durata massima della sessione.</string>
<string name="vault_timeout_policy_in_effect_format" comment="Value will be a number of hours or minutes (15 minutes, or 1 minute)">La tua organizzazione ha impostato il timeout massimo per la sessione a %1$s.</string>
<string name="this_setting_is_managed_by_your_organization">Questa impostazione è gestita dalla tua organizzazione.</string>
<string name="your_organization_has_set_the_default_session_timeout_to_never">La tua organizzazione ha disabilitato il timeout di sessione.</string>
<string name="your_organization_has_set_the_default_session_timeout_to_on_app_restart">La tua organizzazione ha stabilito un timeout di sessione ad ogni riavvio dell\'app.</string>
<string name="vault_timeout_to_large">La scadenza della sessione supera il limite impostato dall\'organizzazione</string>
<string name="disable_personal_vault_export_policy_in_effect">L\'esportazione della cassaforte è negata dalle politiche dell\'organizzazione</string>
<string name="add_account">Aggiungi un account</string>
@@ -586,8 +586,8 @@ Tutte le sessioni attive verranno terminate entro un\'ora.</string>
<string name="api_access_token">Token API (necessario)</string>
<string name="are_you_sure_you_want_to_overwrite_the_current_username">Vuoi davvero sovrascrivere il nome utente attuale?</string>
<string name="generate_username">Genera nome utente</string>
<string name="plus_addressed_email_description">Use your email providers subaddress capabilities</string>
<string name="catch_all_email_description">Use your domains configured catch-all inbox.</string>
<string name="plus_addressed_email_description">Usa le funzionalità di sub-indirizzamento del tuo provider email</string>
<string name="catch_all_email_description">Usa una casella di posta \'catch-all\' di dominio.</string>
<string name="forwarded_email_description">Genera un alias email con un servizio di inoltro esterno.</string>
<string name="accessibility_service_disclosure">Ulteriori informazioni sul servizio di accessibilità</string>
<string name="accessibility_disclosure_text">Questa app utilizza il servizio di accessibilità di sistema per cercare i campi di login e verifica se nella tua cassaforte ci sono corrispondenze per la pagina Web visualizzata o l\'app attiva. Bitwarden non memorizza nessuna delle informazioni consultate dal servizio, e non legge né controlla altri dati durante l\'inserimento delle credenziali.</string>
@@ -690,7 +690,7 @@ Vuoi passare a questo account?</string>
<string name="follow_the_steps_from_duo_to_finish_logging_in">Segui i passaggi da DUO per finire di accedere.</string>
<string name="launch_duo">Avvia DUO</string>
<string name="your_passkey_will_be_saved_to_your_bitwarden_vault_for_x">La tua passkey sarà salvata nella tua cassaforte di Bitwarden per %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Your password will be saved to your Bitwarden vault for %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">La tua password sarà salvata nella tua cassaforte per %1$s</string>
<string name="passkeys_not_supported_for_this_app">Passkey non supportate per questa app</string>
<string name="passkey_operation_failed_because_browser_is_not_privileged">L\'operazione della passkey non è riuscita perché il browser non dispone dei privilegi necessari</string>
<string name="passkey_operation_failed_because_browser_signature_does_not_match">L\'operazione della passkey non è riuscita perché la firma del browser non corrisponde</string>
@@ -917,8 +917,8 @@ Vuoi passare a questo account?</string>
<string name="passkey_operation_failed_because_the_request_is_unsupported">Operazione passkey non riuscita perché la richiesta non è supportata.</string>
<string name="password_operation_failed_because_the_selected_item_does_not_exist">Operazione password non riuscita: l\'elemento selezionato non esiste.</string>
<string name="password_operation_failed_because_no_item_was_selected">Operazione password non riuscita: non è stato selezionato un elemento.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Credential operation failed because the request is invalid.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Credential operation failed because the request is unsupported.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Operazione non riuscita: richiesta non valida.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Operazione non riuscita: richiesta non supportata.</string>
<string name="credential_operation_failed_because_user_verification_attempts_exceeded">Operazione sulle credenziali non riuscita: il limite dei tentativi di verifica è stato superato.</string>
<string name="credential_operation_failed_because_user_is_locked_out">Operazione sulle credenziali non riuscita: l\'utente è bloccato.</string>
<string name="credential_operation_failed_because_the_selected_item_does_not_exist">Operazione sulle credenziali non riuscita: l\'elemento selezionato non esiste.</string>
@@ -1152,10 +1152,7 @@ Vuoi passare a questo account?</string>
<string name="select_a_different_account">Scegli un altro account</string>
<string name="verify_your_account_email_address">Verifica l\'indirizzo email del tuo account</string>
<string name="enter_the_6_digit_code_that_was_emailed_to_the_address_below">Inserisci il codice a 6 cifre che hai ricevuto via email a</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
<string name="lock_app">Blocca l\'app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Usa il metodo di blocco del dispositivo per sbloccare l\'app</string>
<string name="loading_vault_data">Caricamento cassaforte</string>
</resources>

View File

@@ -1172,7 +1172,4 @@
<string name="lock_app">נעל יישום</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">השתמש בשיטת הנעילה של המכשיר שלך כדי לבטל את נעילת היישום</string>
<string name="loading_vault_data">טוען נתוני כספת…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1148,7 +1148,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1148,7 +1148,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1172,7 +1172,4 @@ Ar norite pereiti prie šios paskyros?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -695,7 +695,7 @@ Vai pārslēgties uz šo kontu?</string>
<string name="follow_the_steps_from_duo_to_finish_logging_in">Jāseko Duo norādēm, lai pabeigtu pieteikšanos.</string>
<string name="launch_duo">Palaist Duo</string>
<string name="your_passkey_will_be_saved_to_your_bitwarden_vault_for_x">%1$s piekļuves atslēga tiks saglabāta Bitwarden glabātavā</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Your password will be saved to your Bitwarden vault for %1$s</string>
<string name="your_password_will_be_saved_to_your_bitwarden_vault_for_x">Parole tiks saglabāta Bitwarden glabātavā %1$s</string>
<string name="passkeys_not_supported_for_this_app">Šai lietotnei netiek nodrošinātas piekļuves atslēgas</string>
<string name="passkey_operation_failed_because_browser_is_not_privileged">Darbība ar piekļuves atslēgu neizdevās, jo pārlūkam nav atļauju</string>
<string name="passkey_operation_failed_because_browser_signature_does_not_match">Darbība ar piekļuves atslēgu neizdevās, jo neatbilst pārlūka paraksts</string>
@@ -923,8 +923,8 @@ Vai pārslēgties uz šo kontu?</string>
<string name="passkey_operation_failed_because_the_request_is_unsupported">Darbība ar piekļuves atslēgu neizdevās, jo pieprasījums netiek atbalstīts.</string>
<string name="password_operation_failed_because_the_selected_item_does_not_exist">Darbība ar paroli neizdevās, jo atlasītais vienums nepastāv.</string>
<string name="password_operation_failed_because_no_item_was_selected">Darbība ar paroli neizdevās, jo netika atlasīts neviens vienums.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Credential operation failed because the request is invalid.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Credential operation failed because the request is unsupported.</string>
<string name="credential_operation_failed_because_the_request_is_invalid">Darbība ar piekļuves datiem neizdevās, jo pieprasījums ir nederīgs.</string>
<string name="credential_operation_failed_because_the_request_is_unsupported">Darbība ar piekļuves datiem neizdevās, jo tika izmantots neatbalstīts pieprasījums.</string>
<string name="credential_operation_failed_because_user_verification_attempts_exceeded">Darbība ar paroli neizdevās, jo tika pārsniegts lietotāja apliecināšanas mēģinājumu skaits.</string>
<string name="credential_operation_failed_because_user_is_locked_out">Darbība ar paroli neizdevās, jo lietotājs ir izslēgts.</string>
<string name="credential_operation_failed_because_the_selected_item_does_not_exist">Darbība ar piekļuves datiem neizdevās, jo atlasītais vienums nepastāv.</string>
@@ -1164,7 +1164,4 @@ Vai pārslēgties uz šo kontu?</string>
<string name="lock_app">Aizslēgt lietotni</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Jāizmanto ierīces slēgšanas veids, lai atslēgtu lietotni</string>
<string name="loading_vault_data">Ielādē glabātavas datus…</string>
<string name="compatibility_mode_warning">Saderības režīmu vajadzētu iespējot tikai tad, ja pārlūkā nedarbojas automātiskā aizpilde. Šis iestatījums samazina drošību un varētu ļaut ļaunprātīgām vietnēm pārtvert paroles. Iespējo to tikai tad, ja pieņem šo iespējamo bīstamību!</string>
<string name="use_compatibility_mode_for_browser_autofill">Izmantot saderības režīmu automātiskai aizpildei pārlūkā</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Izmanto mazāk drošu auotmātiskās aizpildes veidu, kas ir saderīgs ar vairāk pārlūkiem.\n<annotation link="learnMore">Uzzināt vairāk par saderības režīmu</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1148,7 +1148,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Vil du bytte til denne kontoen?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Wilt u naar dit account wisselen?</string>
<string name="lock_app">App vergrendelen</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Gebruik de vergrendelingsmethode van je apparaat om de app te ontgrendelen</string>
<string name="loading_vault_data">Kluisdata inladen…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1171,7 +1171,4 @@ Czy chcesz przełączyć się na to konto?</string>
<string name="lock_app">Blokada aplikacji</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Użyj blokady urządzenia, aby odblokować aplikację</string>
<string name="loading_vault_data">Ładowanie danych sejfu…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -33,7 +33,7 @@
<string name="launch">Abrir</string>
<string name="log_in_verb">Entrar</string>
<string name="log_in_noun">Credencial</string>
<string name="log_out">Sair</string>
<string name="log_out">Desconectar</string>
<string name="logout_confirmation">Tem certeza que deseja sair?</string>
<string name="remove_account">Remover conta</string>
<string name="remove_account_confirmation">Tem certeza que deseja remover essa conta?</string>
@@ -273,7 +273,7 @@ A leitura será feita automaticamente.</string>
<string name="vault_is_locked">O cofre está bloqueado</string>
<string name="go_to_my_vault">Ir para o meu cofre</string>
<string name="collections">Coleções</string>
<string name="no_items_collection">Não há itens nesta coleção.</string>
<string name="no_items_collection">Não há itens neste conjunto.</string>
<string name="no_items_folder">Não há itens nesta pasta.</string>
<string name="no_items_trash">Não há itens na lixeira.</string>
<string name="autofill_accessibility_summary">Ajude a preencher campos de nomes de usuário e senhas em outros apps e na web.</string>
@@ -1158,7 +1158,4 @@ quaisquer problema.</string>
<string name="lock_app">Bloquear aplicativo</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use o método de bloqueio do seu dispositivo para desbloquear o aplicativo</string>
<string name="loading_vault_data">Carregando dados do cofre…</string>
<string name="compatibility_mode_warning">O modo de compatibilidade só deve ser ativado se o preenchimento automático não funcionar no seu navegador. Esta configuração reduz a segurança e pode permitir que sites maliciosos capture suas senhas. Apenas ative se você aceitar este risco.</string>
<string name="use_compatibility_mode_for_browser_autofill">Usar modo de compatibilidade para preenchimento automático do navegador</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Usa um método de preenchimento automático menos seguro compatível com mais navegadores.\n<annotation link="learnMore">Saiba mais sobre o modo de compatibilidade</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Pretende mudar para esta conta?</string>
<string name="lock_app">Bloquear app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Utilize o método de bloqueio do seu dispositivo para desbloquear a app</string>
<string name="loading_vault_data">A carregar os dados do cofre…</string>
<string name="compatibility_mode_warning">O modo de compatibilidade só deve ser ativado se o preenchimento automático não funcionar no seu navegador. Esta configuração reduz a segurança e pode permitir que sites maliciosos capturem as suas palavras-passe. Ative-a apenas se aceitar este risco.</string>
<string name="use_compatibility_mode_for_browser_autofill">Utilize o modo de compatibilidade para o preenchimento automático do navegador</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Utiliza um método de preenchimento automático menos seguro, mas compatível com mais navegadores.\n<annotation link="learnMore">Saiba mais sobre o modo de compatibilidade</annotation></string>
</resources>

View File

@@ -1164,7 +1164,4 @@ Doriți să comutați la acest cont?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1172,7 +1172,4 @@
<string name="lock_app">Заблокировать приложение</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Используйте метод блокировки вашего устройства, чтобы разблокировать приложение</string>
<string name="loading_vault_data">Загрузка данных хранилища…</string>
<string name="compatibility_mode_warning">Режим совместимости следует включать только в том случае, если автозаполнение не работает в вашем браузере. Этот параметр снижает защищенность и может позволить вредоносным сайтам перехватывать ваши пароли. Включайте его, только если вы готовы принять этот риск.</string>
<string name="use_compatibility_mode_for_browser_autofill">Использовать режим совместимости для автозаполнения браузера</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Использует менее защищенный метод автозаполнения, совместимый с большим количеством браузеров.\n<annotation link="learnMore">Подробнее\">Узнайте больше о режиме совместимости</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -436,7 +436,7 @@ Skenovanie prebehne automaticky.</string>
<string name="autofill_suggestions_inline">Inline (zobrazí sa na klávesnici)</string>
<string name="autofill_suggestions_popup">Vyskakovacie okno (zobrazí sa cez vstupné pole)</string>
<string name="accessibility">Použiť dostupnosť</string>
<string name="accessibility_description5">Vyžaduje sa pre použitie dlaždice rýchleho automatického vypĺňania.</string>
<string name="accessibility_description5">Vyžaduje sa na použitie dlaždice rýchleho automatického vypĺňania.</string>
<string name="personal_ownership_policy_in_effect">Politika organizácie ovplyvňuje vaše možnosti vlastníctva.</string>
<string name="send">Send</string>
<string name="send_details">Podrobnosti o Sende</string>
@@ -1172,7 +1172,4 @@ Chcete prepnúť na tento účet?</string>
<string name="lock_app">Uzamknúť aplikáciu</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Na odomknutie aplikácie použite metódu uzamknutia zariadenia</string>
<string name="loading_vault_data">Načítavajú sa údaje trezora…</string>
<string name="compatibility_mode_warning">Režim kompatibility by mal byť povolený len vtedy, ak automatické vypĺňanie vo vašom prehliadači nefunguje. Toto nastavenie znižuje bezpečnosť a mohlo by umožniť škodlivým stránkam odchytiť vaše heslá. Povoľte ho len vtedy, ak toto riziko akceptujete.</string>
<string name="use_compatibility_mode_for_browser_autofill">Na automatické vypĺňanie pre prehliadače použiť režim kompatibility</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Používa menej bezpečnú metódu automatického vypĺňania kompatibilnú s viacerými prehliadačmi.\n<annotation link="learnMore">Viac informácií o režime kompatibility</annotation></string>
</resources>

View File

@@ -1172,7 +1172,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1166,7 +1166,4 @@
<string name="lock_app">Закључај апликацију</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Користите метод закључавања уређаја да бисте откључали апликацију</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Vill du byta till detta konto?</string>
<string name="lock_app">Lås app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Använd enhetens låsningsmetod för att låsa upp appen</string>
<string name="loading_vault_data">Läser in valvdata…</string>
<string name="compatibility_mode_warning">Kompatibilitetsläget bör endast aktiveras om automatisk ifyllning inte fungerar i din webbläsare. Denna inställning minskar säkerheten och kan göra det möjligt för skadliga webbplatser att få tillgång till dina lösenord. Aktivera den endast om du accepterar denna risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Använd kompatibilitetsläge för automatisk ifyllning i webbläsaren</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Använder en mindre säker metod för automatisk ifyllning som är kompatibel med fler webbläsare.\n<annotation link="learnMore">Läs mer om kompatibilitetsläge</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1156,7 +1156,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1148,7 +1148,4 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -1155,7 +1155,4 @@ Bu hesaba geçmek ister misiniz?</string>
<string name="lock_app">Uygulamayı kilitle</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Uygulamanın kilidini açmak için cihazınızın kilit yöntemini kullanın</string>
<string name="loading_vault_data">Kasa verileri yükleniyor…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Tarayıcıda otomatik doldurma için uyumluluk modunu kullan</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Daha fazla tarayıcıyla uyumlu ama daha güvensiz bir yöntem kullanır.\n<annotation link="learnMore">Uyumluluk modu hakkında bilgi alın</annotation></string>
</resources>

View File

@@ -1174,7 +1174,4 @@
<string name="lock_app">Заблокувати програму</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Використовуйте метод блокування пристрою для розблокування програми</string>
<string name="loading_vault_data">Завантаження даних сховища…</string>
<string name="compatibility_mode_warning">Режим сумісності необхідно вмикати лише тоді, коли автозаповнення не працює у вашому браузері. Цей параметр знижує рівень безпеки і може дозволити зловмисним сайтам перехоплювати ваші паролі. Вмикайте його, лише якщо розумієте ризик.</string>
<string name="use_compatibility_mode_for_browser_autofill">Використовувати режим сумісності для автозаповнення браузера</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Використовується менш безпечний метод автозаповнення, сумісний з більшістю браузерів.\n<annotation link="learnMore">Докладніше про режим сумісності</annotation></string>
</resources>

View File

@@ -1152,7 +1152,4 @@ các vấn đề.</string>
<string name="lock_app">Khóa ứng dụng</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Sử dụng phương pháp mở khóa thiết bị của bạn để mở khóa ứng dụng</string>
<string name="loading_vault_data">Đang tải dữ liệu kho…</string>
<string name="compatibility_mode_warning">Compatibility mode should only be enabled if autofill doesnt work in your browser. This setting reduces security and could allow malicious sites to capture your passwords. Only enable it if you accept this risk.</string>
<string name="use_compatibility_mode_for_browser_autofill">Use compatibility mode for browser autofill</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">Uses a less secure autofill method compatible with more browsers.\n<annotation link="learnMore">Learn more about compatibility mode</annotation></string>
</resources>

View File

@@ -496,7 +496,7 @@
<string name="fido2_authenticate_web_authn">验证 WebAuthn</string>
<string name="fido2_return_to_app">返回 App</string>
<string name="reset_password_auto_enroll_invite_warning">此组织有一个企业策略,将为您自动注册密码重置。注册后将允许组织管理员更改您的主密码。</string>
<string name="hours_minutes_format" comment="Used to display a number of hours and minutes">%1$s%2$s</string>
<string name="hours_minutes_format" comment="Used to display a number of hours and minutes">%1$s 小时 %2$s 分钟</string>
<plurals name="hours_format" comment="Can be injected into a sentence with %1$s and %2$s">
<item quantity="other">%1$d 小时</item>
</plurals>
@@ -1149,7 +1149,4 @@
<string name="lock_app">锁定 App</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">使用您设备的锁定方式解锁此 App</string>
<string name="loading_vault_data">正在加载密码库数据…</string>
<string name="compatibility_mode_warning">兼容性模式仅应在浏览器自动填充功能无法正常工作时启用。此设置会降低安全性,并可能允许恶意网站窃取您的密码。仅当您接受此风险时才启用它。</string>
<string name="use_compatibility_mode_for_browser_autofill">为浏览器自动填充功能使用兼容性模式</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">使用安全性较低的自动填充方式以兼容更多浏览器。\n<annotation link="learnMore">了解更多有关兼容性模式的信息</annotation></string>
</resources>

View File

@@ -1149,7 +1149,4 @@
<string name="lock_app">鎖定應用程式</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">使用你的裝置鎖定方式來解鎖此應用程式</string>
<string name="loading_vault_data">正在載入密碼庫資料…</string>
<string name="compatibility_mode_warning">只有在您的瀏覽器無法使用自動填入時,才應啟用相容模式。此設定會降低安全性,且可能讓惡意網站取得您的密碼。只有在您能接受此風險時才啟用。</string>
<string name="use_compatibility_mode_for_browser_autofill">對瀏覽器自動填入使用相容模式</string>
<string name="use_a_less_secure_autofill_method_compatible_with_more_browsers">使用安全性較低、但與更多瀏覽器相容的自動填入方式。\n<annotation link="learnMore">進一步了解相容模式</annotation></string>
</resources>

View File

@@ -385,7 +385,7 @@ Scanning will happen automatically.</string>
<string name="send_verification_code_to_email">Send a verification code to your email</string>
<string name="code_sent">Code sent!</string>
<string name="confirm_your_identity">Confirm your identity to continue.</string>
<string name="export_vault_warning">This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it.</string>
<string name="export_vault_warning">For your security, dont share or send this file over unsecured channels (like email), and delete it when youre done.</string>
<string name="export_vault_file_pw_protect_info">This file export will be password protected and require the file password to decrypt.</string>
<string name="export_vault_confirmation_title">Confirm vault export</string>
<string name="warning">Warning</string>
@@ -653,7 +653,8 @@ Do you want to switch to this account?</string>
<string name="invalid_uri">Invalid URI</string>
<string name="the_urix_is_already_blocked">The URI %1$s is already blocked</string>
<string name="login_approved">Login approved</string>
<string name="log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app_need_another_option">Log in with device must be set up in the settings of the Bitwarden app. Need another option?</string>
<string name="log_in_with_device_must_be_set_up_in_the_settings_of_the_bitwarden_app">Log in with device must be set up in the settings of the Bitwarden app.</string>
<string name="need_another_option_view_all_login_options">Need another option? <annotation link="viewAll">View all login options</annotation></string>
<string name="log_in_with_device">Log in with device</string>
<string name="logging_in_on">Logging in on</string>
<string name="logging_in_on_with_colon">Logging in on:</string>
@@ -1041,6 +1042,8 @@ Do you want to switch to this account?</string>
<string name="export">Export</string>
<string name="export_confirmation_title">Confirm export</string>
<string name="export_success">Data exported successfully</string>
<string name="included_in_this_export">Included in this export</string>
<string name="only_codes_stored_locally_on_this_device_will_be_exported">Only codes stored locally on this device will be exported. Synced codes aren\'t included</string>
<string name="security">Security</string>
<string name="too_many_failed_biometric_attempts">Too many failed biometrics attempts.</string>
<string name="version">Version</string>
@@ -1156,4 +1159,5 @@ Do you want to switch to this account?</string>
<string name="lock_app">Lock app</string>
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your devices lock method to unlock the app</string>
<string name="loading_vault_data">Loading vault data…</string>
<string name="resending">Resending</string>
</resources>

View File

@@ -281,65 +281,4 @@ class StringExtensionsTest {
fun `orZeroWidthSpace returns the original value for a non-blank string`() {
assertEquals("test", "test".orZeroWidthSpace())
}
@Suppress("MaxLineLength")
@Test
fun `prefixWwwIfNecessaryOrNull should prefix www when URI is valid and no scheme and no www`() {
val uri = "example.com"
val expected = "www.$uri"
val actual = uri.prefixWwwIfNecessaryOrNull()
assertEquals(expected, actual)
}
@Test
fun `prefixWwwIfNecessaryOrNull should return URI unchanged when starts with www`() {
val uri = "www.example.com"
val actual = uri.prefixWwwIfNecessaryOrNull()
assertEquals(uri, actual)
}
@Test
fun `prefixWwwIfNecessaryOrNull should prefix www when scheme is http and no www`() {
val uri = "http://example.com"
val expected = "http://www.example.com"
val actual = uri.prefixWwwIfNecessaryOrNull()
assertEquals(expected, actual)
}
@Test
fun `prefixWwwIfNecessaryOrNull should prefix www when scheme is https and no www`() {
val uri = "https://example.com"
val expected = "https://www.example.com"
val actual = uri.prefixWwwIfNecessaryOrNull()
assertEquals(expected, actual)
}
@Suppress("MaxLineLength")
@Test
fun `prefixWwwIfNecessaryOrNull should return URI unchanged when scheme is http and www is present`() {
val uri = "http://www.example.com"
val actual = uri.prefixWwwIfNecessaryOrNull()
assertEquals(uri, actual)
}
@Suppress("MaxLineLength")
@Test
fun `prefixWwwIfNecessaryOrNull should return URI unchanged when scheme is https and www is present`() {
val uri = "https://www.example.com"
val actual = uri.prefixWwwIfNecessaryOrNull()
assertEquals(uri, actual)
}
@Test
fun `prefixWwwIfNecessaryOrNull should return null when URI is empty string`() {
val uri = ""
assertNull(uri.prefixWwwIfNecessaryOrNull())
}
@Test
fun `prefixWwwIfNecessaryOrNull should return null when URI is invalid`() {
val invalidUri = "invalid uri"
assertNull(invalidUri.prefixWwwIfNecessaryOrNull())
}
}