mirror of
https://github.com/bitwarden/android.git
synced 2025-12-05 18:46:49 -06:00
Compare commits
13 Commits
f92f7ee601
...
2d4412cda8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d4412cda8 | ||
|
|
3bef282426 | ||
|
|
e1bb3a4b5d | ||
|
|
1904c4ffb9 | ||
|
|
26e7178300 | ||
|
|
2c01abda46 | ||
|
|
b86cbfcd87 | ||
|
|
3f303d3f39 | ||
|
|
ca7a65fc95 | ||
|
|
f02b374e98 | ||
|
|
1a90860080 | ||
|
|
adf83cd315 | ||
|
|
489c0ea8d6 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 {
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -1188,7 +1188,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1171,7 +1171,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1156,7 +1156,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -1156,7 +1156,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">We’ve 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 device’s 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 account’s 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, you’ll 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 organization’s single sign-on portal. Please enter your organization’s 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 provider’s subaddress capabilities</string>
|
||||
<string name="catch_all_email_description">Use your domain’s 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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 doesn’t 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>
|
||||
|
||||
@@ -1148,7 +1148,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -1148,7 +1148,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1156,7 +1156,4 @@
|
||||
<string name="lock_app">Lock app</string>
|
||||
<string name="use_your_devices_lock_method_to_unlock_the_app">Use your device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 device’s 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 doesn’t 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>
|
||||
|
||||
@@ -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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 doesn’t 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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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, don’t share or send this file over unsecured channels (like email), and delete it when you’re 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 device’s lock method to unlock the app</string>
|
||||
<string name="loading_vault_data">Loading vault data…</string>
|
||||
<string name="resending">Resending</string>
|
||||
</resources>
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user