mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
68 Commits
ps/sdk
...
feature/PM
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95ccf1da08 | ||
|
|
ea44a84596 | ||
|
|
62f3fd5b5c | ||
|
|
4abb472998 | ||
|
|
1d541e5b8e | ||
|
|
175b9936b6 | ||
|
|
72e67bd6f2 | ||
|
|
216c6abcf6 | ||
|
|
1014563c75 | ||
|
|
3506269811 | ||
|
|
31487a31bb | ||
|
|
1407aa5655 | ||
|
|
16f59e2698 | ||
|
|
d876b54f45 | ||
|
|
6644e3b449 | ||
|
|
8d98d1d5bd | ||
|
|
3e9711f8f2 | ||
|
|
3af37f01d3 | ||
|
|
43d2d386b1 | ||
|
|
bc5c11b47f | ||
|
|
52843b4181 | ||
|
|
98705e443f | ||
|
|
1332ef7b43 | ||
|
|
04e30c2146 | ||
|
|
f604da13a1 | ||
|
|
dcf9acb51c | ||
|
|
3b087c50ae | ||
|
|
1c13ed9895 | ||
|
|
eeb634e698 | ||
|
|
8bc2df6c8a | ||
|
|
7cd40d4d89 | ||
|
|
bebf23785d | ||
|
|
e78833cbcb | ||
|
|
b7ff636862 | ||
|
|
0288a6659c | ||
|
|
c7fd113f26 | ||
|
|
79241731e7 | ||
|
|
74e9914f5b | ||
|
|
65307f6eab | ||
|
|
e9f83aee90 | ||
|
|
fdaf743868 | ||
|
|
9d6b938ba9 | ||
|
|
1c8328f62d | ||
|
|
f24b82f345 | ||
|
|
37f1a7087e | ||
|
|
6bb654e630 | ||
|
|
fc260f8159 | ||
|
|
bf463926a3 | ||
|
|
c1673a1bbf | ||
|
|
7b44395e1a | ||
|
|
0f3529aab8 | ||
|
|
a72779997c | ||
|
|
49da536c7a | ||
|
|
c985c0a62b | ||
|
|
0f417b8434 | ||
|
|
4f0238122b | ||
|
|
52ff634f00 | ||
|
|
e820537fce | ||
|
|
7130d8a18c | ||
|
|
659d34dfc2 | ||
|
|
6a5c999628 | ||
|
|
3bcb44ea71 | ||
|
|
b108b4e71d | ||
|
|
a72f267558 | ||
|
|
cc75cebdb8 | ||
|
|
3a0510d6b4 | ||
|
|
0c4b88e562 | ||
|
|
ac3b0c2bad |
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Customer Support
|
||||
url: https://bitwarden.com/contact/
|
||||
about: Please contact our customer support for account issues and general customer support.
|
||||
- name: Report mobile autofill failure
|
||||
url: https://docs.google.com/forms/d/e/1FAIpQLScMopHyN7KGJs8hW562VTzbIGL4KcFnx0wJcsW0GYE1BnPiGA/viewform
|
||||
about: We are aware of some situations where the Bitwarden mobile app will not autofill information correctly. This is something the Bitwarden team is actively working on but need your help as a community and active Bitwarden users!
|
||||
@@ -9,9 +12,6 @@ contact_links:
|
||||
- name: Bitwarden Community Forums
|
||||
url: https://community.bitwarden.com
|
||||
about: Please visit the community forums for general community discussion, support and the development roadmap.
|
||||
- name: Customer Support
|
||||
url: https://bitwarden.com/contact/
|
||||
about: Please contact our customer support for account issues and general customer support.
|
||||
- name: Security Issues
|
||||
url: https://hackerone.com/bitwarden
|
||||
about: We use HackerOne to manage security disclosures.
|
||||
|
||||
19
.github/labeler.yml
vendored
Normal file
19
.github/labeler.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
android:
|
||||
- src/App/*
|
||||
- src/Core/*
|
||||
- src/Android/*
|
||||
|
||||
iOS:
|
||||
- src/App/*
|
||||
- src/Core/*
|
||||
- lib/ios/*
|
||||
- src/iOS/*
|
||||
- 'src/iOS.Autofill/*'
|
||||
- 'src/iOS.Core/*'
|
||||
- 'src/iOS.Extension/*'
|
||||
- 'src/iOS.ShareExtension/*'
|
||||
- 'src/iOS.Widget/*'
|
||||
- src/watchOS/*
|
||||
|
||||
watchOS:
|
||||
- src/watchOS/*
|
||||
57
.github/renovate.json
vendored
57
.github/renovate.json
vendored
@@ -1,22 +1,37 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
"schedule:monthly",
|
||||
":maintainLockFilesMonthly",
|
||||
":preserveSemverRanges",
|
||||
":rebaseStalePrs",
|
||||
":disableDependencyDashboard"
|
||||
],
|
||||
"enabledManagers": [
|
||||
"nuget"
|
||||
],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": ["nuget"],
|
||||
"groupName": "Nuget updates",
|
||||
"groupSlug": "nuget",
|
||||
"separateMajorMinor": false
|
||||
}
|
||||
]
|
||||
}
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
":combinePatchMinorReleases",
|
||||
":dependencyDashboard",
|
||||
":maintainLockFilesWeekly",
|
||||
":pinAllExceptPeerDependencies",
|
||||
":prConcurrentLimit10",
|
||||
":rebaseStalePrs",
|
||||
"schedule:weekends",
|
||||
":separateMajorReleases"
|
||||
],
|
||||
"enabledManagers": ["cargo", "github-actions", "npm", "nuget"],
|
||||
"packageRules": [
|
||||
{
|
||||
"groupName": "cargo minor",
|
||||
"matchManagers": ["cargo"],
|
||||
"matchUpdateTypes": ["minor", "patch"]
|
||||
},
|
||||
{
|
||||
"groupName": "gh minor",
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["minor", "patch"]
|
||||
},
|
||||
{
|
||||
"groupName": "npm minor",
|
||||
"matchManagers": ["npm"],
|
||||
"matchUpdateTypes": ["minor", "patch"]
|
||||
},
|
||||
{
|
||||
"groupName": "nuget minor",
|
||||
"matchManagers": ["nuget"],
|
||||
"matchUpdateTypes": ["minor", "patch"]
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
10
.github/workflows/automatic-issue-responses.yml
vendored
10
.github/workflows/automatic-issue-responses.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
# Feature request
|
||||
- if: github.event.label.name == 'feature-request'
|
||||
name: Feature request
|
||||
uses: peter-evans/close-issue@849549ba7c3a595a064c4b2c56f206ee78f93515 # v2.0.0
|
||||
uses: peter-evans/close-issue@276d7966e389d888f011539a86c8920025ea0626 # v3.0.1
|
||||
with:
|
||||
comment: |
|
||||
We use GitHub issues as a place to track bugs and other development related issues. The [Bitwarden Community Forums](https://community.bitwarden.com/) has a [Feature Requests](https://community.bitwarden.com/c/feature-requests) section for submitting, voting for, and discussing requests like this one.
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
# Intended behavior
|
||||
- if: github.event.label.name == 'intended-behavior'
|
||||
name: Intended behaviour
|
||||
uses: peter-evans/close-issue@849549ba7c3a595a064c4b2c56f206ee78f93515 # v2.0.0
|
||||
uses: peter-evans/close-issue@276d7966e389d888f011539a86c8920025ea0626 # v3.0.1
|
||||
with:
|
||||
comment: |
|
||||
Your issue appears to be describing the intended behavior of the software. If you want this to be changed, it would be a feature request.
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
# Customer support request
|
||||
- if: github.event.label.name == 'customer-support'
|
||||
name: Customer Support request
|
||||
uses: peter-evans/close-issue@849549ba7c3a595a064c4b2c56f206ee78f93515 # v2.0.0
|
||||
uses: peter-evans/close-issue@276d7966e389d888f011539a86c8920025ea0626 # v3.0.1
|
||||
with:
|
||||
comment: |
|
||||
We use GitHub issues as a place to track bugs and other development related issues. Your issue appears to be a support request, or would otherwise be better handled by our dedicated Customer Success team.
|
||||
@@ -49,14 +49,14 @@ jobs:
|
||||
# Resolved
|
||||
- if: github.event.label.name == 'resolved'
|
||||
name: Resolved
|
||||
uses: peter-evans/close-issue@849549ba7c3a595a064c4b2c56f206ee78f93515 # v2.0.0
|
||||
uses: peter-evans/close-issue@276d7966e389d888f011539a86c8920025ea0626 # v3.0.1
|
||||
with:
|
||||
comment: |
|
||||
We’ve closed this issue, as it appears the original problem has been resolved. If this happens again or continues to be an problem, please respond to this issue with any additional detail to assist with reproduction and root cause analysis.
|
||||
# Stale
|
||||
- if: github.event.label.name == 'stale'
|
||||
name: Stale
|
||||
uses: peter-evans/close-issue@849549ba7c3a595a064c4b2c56f206ee78f93515 # v2.0.0
|
||||
uses: peter-evans/close-issue@276d7966e389d888f011539a86c8920025ea0626 # v3.0.1
|
||||
with:
|
||||
comment: |
|
||||
As we haven’t heard from you about this problem in some time, this issue will now be closed.
|
||||
|
||||
70
.github/workflows/build.yml
vendored
70
.github/workflows/build.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Set up CLOC
|
||||
run: |
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
@@ -67,12 +67,12 @@ jobs:
|
||||
variant: ["prod", "qa"]
|
||||
steps:
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@b2bc17b761a1d88cab755a776c7922eb26eefbfa # v1.0.6
|
||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||
with:
|
||||
nuget-version: 5.9.0
|
||||
|
||||
- name: Set up MSBuild
|
||||
uses: microsoft/setup-msbuild@ab534842b4bdf384b8aaf93765dc6f721d9f5fab
|
||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
|
||||
|
||||
- name: Setup Windows builder
|
||||
run: choco install checksum --no-progress
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Decrypt secrets
|
||||
@@ -157,7 +157,7 @@ jobs:
|
||||
shell: pwsh
|
||||
|
||||
- name: Report test results
|
||||
uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226
|
||||
uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
|
||||
if: always()
|
||||
with:
|
||||
name: Test Results
|
||||
@@ -191,7 +191,7 @@ jobs:
|
||||
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
|
||||
$packageName = "com.x8bit.bitwarden";
|
||||
|
||||
if ("${{ matrix.variant }}" -ne "prod")
|
||||
if ("${{ matrix.variant }}" -ne "prod")
|
||||
{
|
||||
$packageName = "com.x8bit.bitwarden.${{ matrix.variant }}";
|
||||
}
|
||||
@@ -232,7 +232,7 @@ jobs:
|
||||
shell: pwsh
|
||||
- name: Upload Prod .aab artifact
|
||||
if: ${{ matrix.variant == 'prod' }}
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: com.x8bit.bitwarden.aab
|
||||
path: ./com.x8bit.bitwarden.aab
|
||||
@@ -240,7 +240,7 @@ jobs:
|
||||
|
||||
- name: Upload Prod .apk artifact
|
||||
if: ${{ matrix.variant == 'prod' }}
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: com.x8bit.bitwarden.apk
|
||||
path: ./com.x8bit.bitwarden.apk
|
||||
@@ -248,7 +248,7 @@ jobs:
|
||||
|
||||
- name: Upload Other .apk artifact
|
||||
if: ${{ matrix.variant != 'prod' }}
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: com.x8bit.bitwarden.${{ matrix.variant }}.apk
|
||||
path: ./com.x8bit.bitwarden.${{ matrix.variant }}.apk
|
||||
@@ -268,7 +268,7 @@ jobs:
|
||||
|
||||
- name: Upload .apk sha file for prod
|
||||
if: ${{ matrix.variant == 'prod' }}
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: bw-android-apk-sha256.txt
|
||||
path: ./bw-android-apk-sha256.txt
|
||||
@@ -276,7 +276,7 @@ jobs:
|
||||
|
||||
- name: Upload .apk sha file for other
|
||||
if: ${{ matrix.variant != 'prod' }}
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: bw-android-${{ matrix.variant }}-apk-sha256.txt
|
||||
path: ./bw-android-${{ matrix.variant }}-apk-sha256.txt
|
||||
@@ -303,12 +303,12 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@b2bc17b761a1d88cab755a776c7922eb26eefbfa # v1.0.6
|
||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||
with:
|
||||
nuget-version: 5.9.0
|
||||
|
||||
- name: Set up MSBuild
|
||||
uses: microsoft/setup-msbuild@ab534842b4bdf384b8aaf93765dc6f721d9f5fab
|
||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
|
||||
|
||||
- name: Setup Windows builder
|
||||
run: choco install checksum --no-progress
|
||||
@@ -342,7 +342,7 @@ jobs:
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Decrypt secrets
|
||||
env:
|
||||
@@ -477,7 +477,7 @@ jobs:
|
||||
shell: pwsh
|
||||
|
||||
- name: Upload F-Droid .apk artifact
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: com.x8bit.bitwarden-fdroid.apk
|
||||
path: ./com.x8bit.bitwarden-fdroid.apk
|
||||
@@ -489,7 +489,7 @@ jobs:
|
||||
-t sha256 | Out-File -Encoding ASCII ./bw-fdroid-apk-sha256.txt
|
||||
|
||||
- name: Upload F-Droid sha file
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: bw-fdroid-apk-sha256.txt
|
||||
path: ./bw-fdroid-apk-sha256.txt
|
||||
@@ -502,7 +502,7 @@ jobs:
|
||||
needs: setup
|
||||
steps:
|
||||
- name: Setup NuGet
|
||||
uses: nuget/setup-nuget@b2bc17b761a1d88cab755a776c7922eb26eefbfa # v1.0.6
|
||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||
with:
|
||||
nuget-version: 5.9.0
|
||||
|
||||
@@ -515,19 +515,19 @@ jobs:
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
- name: Login to Azure - Prod Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
env:
|
||||
KEYVAULT: bitwarden-prod-kv
|
||||
KEYVAULT: bitwarden-ci
|
||||
SECRETS: |
|
||||
appcenter-ios-token
|
||||
run: |
|
||||
@@ -698,7 +698,7 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Upload App Store .ipa & dSYMs artifacts
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
|
||||
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||
with:
|
||||
name: Bitwarden iOS
|
||||
path: |
|
||||
@@ -771,17 +771,17 @@ jobs:
|
||||
_CROWDIN_PROJECT_ID: "269690"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Login to Azure
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
env:
|
||||
KEYVAULT: bitwarden-prod-kv
|
||||
KEYVAULT: bitwarden-ci
|
||||
SECRETS: |
|
||||
crowdin-api-token
|
||||
run: |
|
||||
@@ -793,7 +793,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Upload Sources
|
||||
uses: crowdin/github-action@9237b4cb361788dfce63feb2e2f15c09e2fe7415
|
||||
uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||
@@ -839,17 +839,17 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Login to Azure - Prod Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
||||
if: failure()
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
if: failure()
|
||||
env:
|
||||
KEYVAULT: bitwarden-prod-kv
|
||||
KEYVAULT: bitwarden-ci
|
||||
SECRETS: |
|
||||
devops-alerts-slack-webhook-url
|
||||
run: |
|
||||
@@ -861,7 +861,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: act10ns/slack@da3191ebe2e67f49b46880b4633f5591a96d1d33
|
||||
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
|
||||
if: failure()
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||
|
||||
16
.github/workflows/crowdin-pull.yml
vendored
16
.github/workflows/crowdin-pull.yml
vendored
@@ -15,22 +15,22 @@ jobs:
|
||||
_CROWDIN_PROJECT_ID: "269690"
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Login to Azure
|
||||
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
keyvault: "bitwarden-prod-kv"
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
|
||||
|
||||
- name: Download translations
|
||||
uses: crowdin/github-action@12143a68c213f3c6d9913c9e5023224f7231face
|
||||
uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||
@@ -48,4 +48,4 @@ jobs:
|
||||
pull_request_title: "Autosync Crowdin Translations"
|
||||
pull_request_body: "Autosync the updated translations"
|
||||
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
|
||||
gpg_passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
||||
gpg_passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
||||
|
||||
2
.github/workflows/enforce-labels.yml
vendored
2
.github/workflows/enforce-labels.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Enforce Label
|
||||
uses: yogevbd/enforce-label-action@8d1e1709b1011e6d90400a0e6cf7c0b77aa5efeb
|
||||
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
|
||||
with:
|
||||
BANNED_LABELS: "hold,needs-qa"
|
||||
BANNED_LABELS_DESCRIPTION: "PRs with the hold or needs-qa labels cannot be merged"
|
||||
|
||||
17
.github/workflows/pr-labeler.yml
vendored
Normal file
17
.github/workflows/pr-labeler.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: "Pull Request Labeler"
|
||||
|
||||
on:
|
||||
pull_request_target: {}
|
||||
|
||||
jobs:
|
||||
labeler:
|
||||
name: "Pull Request Labeler"
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/labeler@ba790c862c380240c6d5e7427be5ace9a05c754b # v4.0.3
|
||||
with:
|
||||
sync-labels: true
|
||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -38,11 +38,11 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Check Release Version
|
||||
id: version
|
||||
uses: bitwarden/gh-actions/release-version-check@8f055ef543c7433c967a1b9b04a0f230923233bb
|
||||
uses: bitwarden/gh-actions/release-version-check@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
release-type: ${{ github.event.inputs.release_type }}
|
||||
project-type: xamarin
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
|
||||
- name: Create GitHub deployment
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
uses: chrnorm/deployment-action@1b599fe41a0ef1f95191e7f2eec4743f2d7dfc48
|
||||
uses: chrnorm/deployment-action@d42cde7132fcec920de534fffc3be83794335c00 # v2.0.5
|
||||
id: deployment
|
||||
with:
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
|
||||
- name: Download all artifacts
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
|
||||
- name: Dry Run - Download all artifacts
|
||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
|
||||
- name: Update deployment status to Success
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }}
|
||||
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
|
||||
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
|
||||
with:
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
state: 'success'
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
- name: Update deployment status to Failure
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }}
|
||||
uses: chrnorm/deployment-status@07b3930847f65e71c9c6802ff5a402f6dfb46b86
|
||||
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
|
||||
with:
|
||||
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
state: 'failure'
|
||||
@@ -126,11 +126,11 @@ jobs:
|
||||
if: inputs.fdroid_publish
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Download F-Droid .apk artifact
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
|
||||
- name: Dry Run - Download F-Droid .apk artifact
|
||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||
uses: dawidd6/action-download-artifact@575b1e4167df67acf7e692af784566618b23c71e # v2.17.10
|
||||
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
|
||||
with:
|
||||
workflow: build.yml
|
||||
workflow_conclusion: success
|
||||
|
||||
4
.github/workflows/version-auto-bump.yml
vendored
4
.github/workflows/version-auto-bump.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
version_number: ${{ steps.version.outputs.new-version }}
|
||||
steps:
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Calculate bumped version
|
||||
id: version
|
||||
@@ -40,6 +40,6 @@ jobs:
|
||||
- name: Bump version to ${{ needs.setup.outputs.version_number }}
|
||||
uses: ./.github/workflows/version-bump.yml
|
||||
secrets:
|
||||
AZURE_PROD_KV_CREDENTIALS: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
AZURE_PROD_KV_CREDENTIALS: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
with:
|
||||
version_number: ${{ needs.setup.outputs.version_number }}
|
||||
|
||||
25
.github/workflows/version-bump.yml
vendored
25
.github/workflows/version-bump.yml
vendored
@@ -11,6 +11,7 @@ on:
|
||||
inputs:
|
||||
version_number:
|
||||
required: true
|
||||
type: string
|
||||
secrets:
|
||||
AZURE_PROD_KV_CREDENTIALS:
|
||||
required: true
|
||||
@@ -21,22 +22,22 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: Login to Azure - Prod Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
keyvault: "bitwarden-prod-kv"
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@c8bb57c57e8df1be8c73ff3d59deab1dbc00e0d1
|
||||
uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5.2.0
|
||||
with:
|
||||
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
|
||||
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
||||
@@ -47,31 +48,31 @@ jobs:
|
||||
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
|
||||
|
||||
- name: Bump Version - Android XML
|
||||
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
|
||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
version: ${{ github.event.inputs.version_number }}
|
||||
file_path: "./src/Android/Properties/AndroidManifest.xml"
|
||||
|
||||
- name: Bump Version - iOS.Autofill
|
||||
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
|
||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
version: ${{ github.event.inputs.version_number }}
|
||||
file_path: "./src/iOS.Autofill/Info.plist"
|
||||
|
||||
- name: Bump Version - iOS.Extension
|
||||
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
|
||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
version: ${{ github.event.inputs.version_number }}
|
||||
file_path: "./src/iOS.Extension/Info.plist"
|
||||
|
||||
- name: Bump Version - iOS.ShareExtension
|
||||
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
|
||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
version: ${{ github.event.inputs.version_number }}
|
||||
file_path: "./src/iOS.ShareExtension/Info.plist"
|
||||
|
||||
- name: Bump Version - iOS
|
||||
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
|
||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
with:
|
||||
version: ${{ github.event.inputs.version_number }}
|
||||
file_path: "./src/iOS/Info.plist"
|
||||
|
||||
2
.github/workflows/workflow-linter.yml
vendored
2
.github/workflows/workflow-linter.yml
vendored
@@ -8,4 +8,4 @@ on:
|
||||
|
||||
jobs:
|
||||
call-workflow:
|
||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@master
|
||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@34ecb67b2a357795dc893549df0795e7383ff50f
|
||||
|
||||
@@ -46,6 +46,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\i
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamariniOS17CredentialProviderBinding", "lib\ios\iOS17CredentialProvider\XamariniOS17CredentialProvider\XamariniOS17CredentialProviderBinding\XamariniOS17CredentialProviderBinding.csproj", "{63938BA1-0F72-4BFD-B7A4-823C146E43B4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||
@@ -446,6 +448,36 @@ Global
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.Build.0 = Release|iPhone
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.FDroid|iPhone.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -464,6 +496,7 @@ Global
|
||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
||||
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 25.0.1706.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamariniOS17CredentialProviderBinding", "XamariniOS17CredentialProviderBinding\XamariniOS17CredentialProviderBinding.csproj", "{63938BA1-0F72-4BFD-B7A4-823C146E43B4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{63938BA1-0F72-4BFD-B7A4-823C146E43B4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5EE0FEF7-C01A-4CAF-BCF0-3A1B818D056A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using AuthenticationServices;
|
||||
using Foundation;
|
||||
using ObjCRuntime;
|
||||
|
||||
namespace XamariniOS17CredentialProviderBinding
|
||||
{
|
||||
interface IASCredentialProviderCompatDelegate { }
|
||||
|
||||
// @protocol ASCredentialProviderCompatDelegate
|
||||
[Protocol, Model(AutoGeneratedName = true)]
|
||||
interface ASCredentialProviderCompatDelegate
|
||||
{
|
||||
// @required -(void)prepareInterfaceToProvideCredentialCompatFor:(ASCredentialRequestCompat * _Nonnull)credentialRequest;
|
||||
[iOS(17, 0)]
|
||||
[Abstract]
|
||||
[Export("prepareInterfaceToProvideCredentialCompatFor:")]
|
||||
void PrepareInterfaceToProvideCredentialCompatFor(ASCredentialRequestCompat credentialRequest);
|
||||
|
||||
// @required -(void)provideCredentialWithoutUserInteractionCompatFor:(ASCredentialRequestCompat * _Nonnull)credentialRequest;
|
||||
[iOS(17, 0)]
|
||||
[Abstract]
|
||||
[Export("provideCredentialWithoutUserInteractionCompatFor:")]
|
||||
void ProvideCredentialWithoutUserInteractionCompatFor(ASCredentialRequestCompat credentialRequest);
|
||||
|
||||
// @required -(void)prepareInterfaceCompatForPasskeyRegistration:(ASCredentialRequestCompat * _Nonnull)registrationRequest;
|
||||
[iOS(17, 0)]
|
||||
[Abstract]
|
||||
[Export("prepareInterfaceCompatForPasskeyRegistration:")]
|
||||
void PrepareInterfaceCompatForPasskeyRegistration(ASCredentialRequestCompat registrationRequest);
|
||||
}
|
||||
|
||||
// @interface ASCredentialRequestCompat : NSObject
|
||||
[iOS(17, 0)]
|
||||
[BaseType (typeof(NSObject))]
|
||||
[DisableDefaultCtor]
|
||||
interface ASCredentialRequestCompat
|
||||
{
|
||||
// @property (nonatomic) enum ASCredentialRequestCompatType type;
|
||||
[Export("type", ArgumentSemantic.Assign)]
|
||||
ASCredentialRequestCompatType Type { get; set; }
|
||||
|
||||
// @property (nonatomic, strong) id<ASCredentialIdentity> _Nonnull credentialIdentity;
|
||||
//[Export("credentialIdentity", ArgumentSemantic.Strong)]
|
||||
//ASCredentialIdentity CredentialIdentity { get; set; }
|
||||
|
||||
|
||||
// @property (readonly, nonatomic, strong) ASPasswordCredentialIdentity * _Nullable passwordCredentialIdentity;
|
||||
[iOS(17, 0)]
|
||||
[NullAllowed, Export("passwordCredentialIdentity", ArgumentSemantic.Strong)]
|
||||
ASPasswordCredentialIdentity PasswordCredentialIdentity { get; }
|
||||
|
||||
// @property (readonly, nonatomic, strong) ASPasskeyCredentialIdentityCompat * _Nullable passkeyCredentialIdentity;
|
||||
[iOS(17, 0)]
|
||||
[NullAllowed, Export("passkeyCredentialIdentity", ArgumentSemantic.Strong)]
|
||||
ASPasskeyCredentialIdentityCompat PasskeyCredentialIdentity { get; }
|
||||
}
|
||||
|
||||
// @interface ASPasskeyCredentialIdentityCompat : NSObject
|
||||
[BaseType(typeof(NSObject))]
|
||||
[DisableDefaultCtor]
|
||||
interface ASPasskeyCredentialIdentityCompat
|
||||
{
|
||||
// @property (copy, nonatomic) NSString * _Nonnull relyingPartyIdentifier;
|
||||
[Export("relyingPartyIdentifier")]
|
||||
string RelyingPartyIdentifier { get; set; }
|
||||
|
||||
// @property (copy, nonatomic) NSString * _Nonnull userName;
|
||||
[Export("userName")]
|
||||
string UserName { get; set; }
|
||||
|
||||
// @property (copy, nonatomic) NSData * _Nonnull credentialID;
|
||||
[Export("credentialID", ArgumentSemantic.Copy)]
|
||||
NSData CredentialID { get; set; }
|
||||
|
||||
// @property (copy, nonatomic) NSData * _Nonnull userHandle;
|
||||
[Export("userHandle", ArgumentSemantic.Copy)]
|
||||
NSData UserHandle { get; set; }
|
||||
|
||||
// @property (copy, nonatomic) NSString * _Nullable recordIdentifier;
|
||||
[NullAllowed, Export("recordIdentifier")]
|
||||
string RecordIdentifier { get; set; }
|
||||
|
||||
// @property (nonatomic) NSInteger rank;
|
||||
[Export("rank")]
|
||||
nint Rank { get; set; }
|
||||
}
|
||||
|
||||
// @interface BaseASCredentialProviderViewController : ASCredentialProviderViewController
|
||||
[BaseType (typeof(ASCredentialProviderViewController))]
|
||||
interface BaseASCredentialProviderViewController
|
||||
{
|
||||
// -(void)prepareInterfaceToProvideCredentialForRequest:(id<ASCredentialRequest> _Nonnull)credentialRequest;
|
||||
//[Export ("prepareInterfaceToProvideCredentialForRequest:")]
|
||||
//void PrepareInterfaceToProvideCredentialForRequest (ASCredentialRequest credentialRequest);
|
||||
|
||||
//// -(void)provideCredentialWithoutUserInteractionForRequest:(id<ASCredentialRequest> _Nonnull)credentialRequest;
|
||||
//[Export ("provideCredentialWithoutUserInteractionForRequest:")]
|
||||
//void ProvideCredentialWithoutUserInteractionForRequest (ASCredentialRequest credentialRequest);
|
||||
|
||||
//// -(void)prepareInterfaceForPasskeyRegistration:(id<ASCredentialRequest> _Nonnull)registrationRequest;
|
||||
//[Export ("prepareInterfaceForPasskeyRegistration:")]
|
||||
//void PrepareInterfaceForPasskeyRegistration (ASCredentialRequest registrationRequest);
|
||||
|
||||
// -(void)prepareInterfaceToProvideCredentialCompatFor:(ASCredentialRequestCompat * _Nonnull)credentialRequest;
|
||||
//[Export ("prepareInterfaceToProvideCredentialCompatFor:")]
|
||||
// [Abstract]
|
||||
// void PrepareInterfaceToProvideCredentialCompatFor (ASCredentialRequestCompat credentialRequest);
|
||||
|
||||
//// -(void)provideCredentialWithoutUserInteractionCompatFor:(ASCredentialRequestCompat * _Nonnull)credentialRequest;
|
||||
//[Export ("provideCredentialWithoutUserInteractionCompatFor:")]
|
||||
// [Abstract]
|
||||
// void ProvideCredentialWithoutUserInteractionCompatFor (ASCredentialRequestCompat credentialRequest);
|
||||
|
||||
//// -(void)prepareInterfaceCompatForPasskeyRegistration:(ASCredentialRequestCompat * _Nonnull)registrationRequest;
|
||||
//[Export ("prepareInterfaceCompatForPasskeyRegistration:")]
|
||||
// [Abstract]
|
||||
// void PrepareInterfaceCompatForPasskeyRegistration (ASCredentialRequestCompat registrationRequest);
|
||||
|
||||
[iOS(17, 0)]
|
||||
[Export("SetCompatDelegate:")]
|
||||
void SetCompatDelegate(IASCredentialProviderCompatDelegate @delegate);
|
||||
|
||||
// -(instancetype _Nonnull)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil __attribute__((objc_designated_initializer));
|
||||
[Export ("initWithNibName:bundle:")]
|
||||
[DesignatedInitializer]
|
||||
IntPtr Constructor ([NullAllowed] string nibNameOrNil, [NullAllowed] NSBundle nibBundleOrNil);
|
||||
|
||||
//// -(instancetype _Nullable)initWithCoder:(NSCoder * _Nonnull)coder __attribute__((objc_designated_initializer));
|
||||
//[Export ("initWithCoder:")]
|
||||
//[DesignatedInitializer]
|
||||
// IntPtr Constructor (NSCoder coder);
|
||||
}
|
||||
|
||||
// @interface MyTest : NSObject
|
||||
[BaseType(typeof(NSObject))]
|
||||
//[DisableDefaultCtor]
|
||||
interface MyTest
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
using Foundation;
|
||||
|
||||
// This attribute allows you to mark your assemblies as “safe to link”.
|
||||
// When the attribute is present, the linker—if enabled—will process the assembly
|
||||
// even if you’re using the “Link SDK assemblies only” option, which is the default for device builds.
|
||||
|
||||
[assembly: LinkerSafe]
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("NativeLibrary")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("NativeLibrary")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using ObjCRuntime;
|
||||
|
||||
namespace XamariniOS17CredentialProviderBinding
|
||||
{
|
||||
[Native]
|
||||
public enum ASCredentialRequestCompatType : long
|
||||
{
|
||||
word = 0,
|
||||
keyAssertion = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectTypeGuids>{8FFB629D-F513-41CE-95D2-7ECE97B6EEEC};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<ProjectGuid>{63938BA1-0F72-4BFD-B7A4-823C146E43B4}</ProjectGuid>
|
||||
<TemplateGuid>{b6f3ff35-79b2-4f25-a2fc-60a7cf61013b}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>NativeLibrary</RootNamespace>
|
||||
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
|
||||
<AssemblyName>NativeLibrary</AssemblyName>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Xamarin.iOS" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ObjcBindingApiDefinition Include="ApiDefinitions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ObjcBindingCoreSource Include="StructsAndEnums.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<NativeReference Include="..\..\iOS17CredentialProvider\build\Release-fat\iOS17CredentialProvider.framework">
|
||||
<Kind>Framework</Kind>
|
||||
<SmartLink>True</SmartLink>
|
||||
<ForceLoad>False</ForceLoad>
|
||||
<WeakFrameworks>Foundation AuthenticationServices</WeakFrameworks>
|
||||
</NativeReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.ObjCBinding.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
echo "Building framework"
|
||||
|
||||
xcodebuild -sdk iphonesimulator17.0 -project "iOS17CredentialProvider.xcodeproj" -configuration Release -arch x86_64
|
||||
xcodebuild -sdk iphoneos17.0 -project "iOS17CredentialProvider.xcodeproj" -configuration Release
|
||||
cd build
|
||||
cp -R "Release-iphoneos" "Release-fat"
|
||||
cp -R "Release-iphonesimulator/iOS17CredentialProvider.framework/Modules/iOS17CredentialProvider.swiftmodule/" "Release-fat/iOS17CredentialProvider.framework/Modules/iOS17CredentialProvider.swiftmodule/"
|
||||
lipo -create -output "Release-fat/iOS17CredentialProvider.framework/iOS17CredentialProvider" "Release-iphoneos/iOS17CredentialProvider.framework/iOS17CredentialProvider" "Release-iphonesimulator/iOS17CredentialProvider.framework/iOS17CredentialProvider"
|
||||
|
||||
echo "Sharpie creating binding definitions"
|
||||
|
||||
sharpie bind --sdk=iphoneos17.0 --output="XamarinApiDef" --namespace="Binding" --scope="Release-iphoneos/iOS17CredentialProvider.framework/Headers/" "Release-iphoneos/iOS17CredentialProvider.framework/Headers/iOS17CredentialProvider-Swift.h"
|
||||
|
||||
echo "Done!"
|
||||
@@ -0,0 +1,357 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
B72040A62A4E421C00E62648 /* iOS17CredentialProvider.docc in Sources */ = {isa = PBXBuildFile; fileRef = B72040A52A4E421C00E62648 /* iOS17CredentialProvider.docc */; };
|
||||
B72040A72A4E421C00E62648 /* iOS17CredentialProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = B72040A42A4E421C00E62648 /* iOS17CredentialProvider.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
B72040AE2A535D6500E62648 /* BaseASCredentialProviderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B72040AD2A535D6500E62648 /* BaseASCredentialProviderViewController.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
B72040A12A4E421C00E62648 /* iOS17CredentialProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = iOS17CredentialProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B72040A42A4E421C00E62648 /* iOS17CredentialProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = iOS17CredentialProvider.h; sourceTree = "<group>"; };
|
||||
B72040A52A4E421C00E62648 /* iOS17CredentialProvider.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = iOS17CredentialProvider.docc; sourceTree = "<group>"; };
|
||||
B72040AD2A535D6500E62648 /* BaseASCredentialProviderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseASCredentialProviderViewController.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
B720409E2A4E421C00E62648 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
B72040972A4E421C00E62648 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B72040A32A4E421C00E62648 /* iOS17CredentialProvider */,
|
||||
B72040A22A4E421C00E62648 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B72040A22A4E421C00E62648 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B72040A12A4E421C00E62648 /* iOS17CredentialProvider.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B72040A32A4E421C00E62648 /* iOS17CredentialProvider */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B72040A42A4E421C00E62648 /* iOS17CredentialProvider.h */,
|
||||
B72040A52A4E421C00E62648 /* iOS17CredentialProvider.docc */,
|
||||
B72040AD2A535D6500E62648 /* BaseASCredentialProviderViewController.swift */,
|
||||
);
|
||||
path = "iOS17CredentialProvider";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
B720409C2A4E421C00E62648 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B72040A72A4E421C00E62648 /* iOS17CredentialProvider.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
B72040A02A4E421C00E62648 /* iOS17CredentialProvider */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B72040AA2A4E421C00E62648 /* Build configuration list for PBXNativeTarget "iOS17CredentialProvider" */;
|
||||
buildPhases = (
|
||||
B720409C2A4E421C00E62648 /* Headers */,
|
||||
B720409D2A4E421C00E62648 /* Sources */,
|
||||
B720409E2A4E421C00E62648 /* Frameworks */,
|
||||
B720409F2A4E421C00E62648 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "iOS17CredentialProvider";
|
||||
productName = "iOS17CredentialProvider";
|
||||
productReference = B72040A12A4E421C00E62648 /* iOS17CredentialProvider.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
B72040982A4E421C00E62648 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastUpgradeCheck = 1500;
|
||||
TargetAttributes = {
|
||||
B72040A02A4E421C00E62648 = {
|
||||
CreatedOnToolsVersion = 15.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = B720409B2A4E421C00E62648 /* Build configuration list for PBXProject "iOS17CredentialProvider" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = B72040972A4E421C00E62648;
|
||||
productRefGroup = B72040A22A4E421C00E62648 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B72040A02A4E421C00E62648 /* iOS17CredentialProvider */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
B720409F2A4E421C00E62648 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
B720409D2A4E421C00E62648 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B72040A62A4E421C00E62648 /* iOS17CredentialProvider.docc in Sources */,
|
||||
B72040AE2A535D6500E62648 /* BaseASCredentialProviderViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
B72040A82A4E421C00E62648 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B72040A92A4E421C00E62648 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B72040AB2A4E421C00E62648 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = LTZ2PFU5D6;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.8bit.bitwarden.iOS17CredentialProvider";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B72040AC2A4E421C00E62648 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = LTZ2PFU5D6;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
ENABLE_MODULE_VERIFIER = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@loader_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
|
||||
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.8bit.bitwarden.iOS17CredentialProvider";
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
B720409B2A4E421C00E62648 /* Build configuration list for PBXProject "iOS17CredentialProvider" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B72040A82A4E421C00E62648 /* Debug */,
|
||||
B72040A92A4E421C00E62648 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B72040AA2A4E421C00E62648 /* Build configuration list for PBXNativeTarget "iOS17CredentialProvider" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B72040AB2A4E421C00E62648 /* Debug */,
|
||||
B72040AC2A4E421C00E62648 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = B72040982A4E421C00E62648 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1500"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B72040A02A4E421C00E62648"
|
||||
BuildableName = "iOS17CredentialProvider.framework"
|
||||
BlueprintName = "iOS17CredentialProvider"
|
||||
ReferencedContainer = "container:iOS17CredentialProvider.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B72040A02A4E421C00E62648"
|
||||
BuildableName = "iOS17CredentialProvider.framework"
|
||||
BlueprintName = "iOS17CredentialProvider"
|
||||
ReferencedContainer = "container:iOS17CredentialProvider.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// BaseASCredentialProviderViewController.swift
|
||||
// iOS17CredentialProvider
|
||||
//
|
||||
// Created by Federico Maccaroni on 03/07/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AuthenticationServices
|
||||
|
||||
@objc(ASCredentialRequestCompatType)
|
||||
public enum ASCredentialRequestCompatType : Int, @unchecked Sendable {
|
||||
case password = 0
|
||||
|
||||
case passkeyAssertion = 1
|
||||
}
|
||||
|
||||
@objc(ASPasskeyCredentialIdentityCompat)
|
||||
public class ASPasskeyCredentialIdentityCompat : NSObject {
|
||||
|
||||
init(relyingPartyIdentifier: String, userName: String, credentialID: Data, userHandle: Data, recordIdentifier: String? = nil, rank: Int) {
|
||||
self.relyingPartyIdentifier = relyingPartyIdentifier
|
||||
self.userName = userName
|
||||
self.credentialID = credentialID
|
||||
self.userHandle = userHandle
|
||||
self.recordIdentifier = recordIdentifier
|
||||
self.rank = rank
|
||||
}
|
||||
|
||||
/** The relying party identifier of this passkey credential.
|
||||
@discussion This field is reported as the serviceIdentifier property of ASCredentialIdentity.
|
||||
*/
|
||||
@objc
|
||||
public var relyingPartyIdentifier: String
|
||||
|
||||
|
||||
/** The user name of this passkey credential.
|
||||
@discussion This field is reported as the user property of ASCredentialIdentity.
|
||||
*/
|
||||
@objc
|
||||
public var userName: String
|
||||
|
||||
|
||||
/** The credential ID of this passkey credential.
|
||||
@discussion This field is used to identify the correct credential to use based on relying party request parameters.
|
||||
*/
|
||||
@objc
|
||||
public var credentialID: Data
|
||||
|
||||
|
||||
/** The user handle of this passkey credential.
|
||||
@discussion This field is used to identify the correct credential to use based on relying party request parameters.
|
||||
*/
|
||||
@objc
|
||||
public var userHandle: Data
|
||||
|
||||
|
||||
/** Get the record identifier.
|
||||
@result The record identifier.
|
||||
@discussion You can utilize the record identifier to uniquely identify the credential identity in your local database.
|
||||
*/
|
||||
@objc
|
||||
public var recordIdentifier: String?
|
||||
|
||||
|
||||
/** Get or set the rank of the credential identity object.
|
||||
@discussion The system may utilize the rank to decide which credential identity precedes the other
|
||||
if two identities have the same service identifier. A credential identity with a larger rank value
|
||||
precedes one with a smaller value if both credential identities have the same service identifier.
|
||||
The default value of this property is 0.
|
||||
*/
|
||||
@objc
|
||||
public var rank: Int
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
@objc(ASCredentialRequestCompat)
|
||||
public class ASCredentialRequestCompat : NSObject {
|
||||
|
||||
/** The type of credential used for this request.
|
||||
*/
|
||||
@objc
|
||||
public var type: ASCredentialRequestCompatType
|
||||
|
||||
|
||||
/** The credential identity selected by the user to authenticate.
|
||||
*/
|
||||
@available(iOS 17.0, *)
|
||||
var credentialIdentity: ASCredentialIdentity
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
@objc
|
||||
public var passwordCredentialIdentity: ASPasswordCredentialIdentity? {
|
||||
guard type == .password, let password = credentialIdentity as? ASPasswordCredentialIdentity else {
|
||||
return nil
|
||||
}
|
||||
return password
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
@objc
|
||||
public var passkeyCredentialIdentity: ASPasskeyCredentialIdentityCompat? {
|
||||
guard type == .passkeyAssertion, let passkey = credentialIdentity as? ASPasskeyCredentialIdentity else {
|
||||
return nil
|
||||
}
|
||||
return ASPasskeyCredentialIdentityCompat(relyingPartyIdentifier: passkey.relyingPartyIdentifier, userName: passkey.userName, credentialID: passkey.credentialID, userHandle: passkey.userHandle, recordIdentifier: passkey.recordIdentifier, rank: passkey.rank)
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
init(type: ASCredentialRequestCompatType, credentialIdentity: ASCredentialIdentity) {
|
||||
self.type = type
|
||||
self.credentialIdentity = credentialIdentity
|
||||
}
|
||||
}
|
||||
|
||||
@objc(BaseASCredentialProviderViewController)
|
||||
open class BaseASCredentialProviderViewController : ASCredentialProviderViewController
|
||||
{
|
||||
// MARK: iOS 17 new methods
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
override final public func prepareInterfaceToProvideCredential(for credentialRequest: ASCredentialRequest) {
|
||||
guard let compatDelegate = compatDelegate else {
|
||||
return
|
||||
}
|
||||
compatDelegate.prepareInterfaceToProvideCredentialCompat(for: convertRequestToCompat(from: credentialRequest))
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
override final public func provideCredentialWithoutUserInteraction(for credentialRequest: ASCredentialRequest) {
|
||||
guard let compatDelegate = compatDelegate else {
|
||||
return
|
||||
}
|
||||
compatDelegate.provideCredentialWithoutUserInteractionCompat(for: convertRequestToCompat(from: credentialRequest))
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
override final public func prepareInterface(forPasskeyRegistration registrationRequest: ASCredentialRequest) {
|
||||
guard let compatDelegate = compatDelegate else {
|
||||
return
|
||||
}
|
||||
compatDelegate.prepareInterfaceCompat(forPasskeyRegistration: convertRequestToCompat(from: registrationRequest))
|
||||
}
|
||||
|
||||
// MARK: Compat
|
||||
|
||||
var compatDelegate: ASCredentialProviderCompatDelegate? = nil;
|
||||
|
||||
@objc
|
||||
@available(iOS 17.0, *)
|
||||
public func SetCompatDelegate(_ delegate: ASCredentialProviderCompatDelegate)
|
||||
{
|
||||
compatDelegate = delegate
|
||||
}
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
func convertRequestToCompat(from credentialRequest: ASCredentialRequest) -> ASCredentialRequestCompat {
|
||||
return ASCredentialRequestCompat(
|
||||
type: credentialRequest.type == .password ? .password : .passkeyAssertion,
|
||||
credentialIdentity: credentialRequest.credentialIdentity)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(ASCredentialProviderCompatDelegate)
|
||||
public protocol ASCredentialProviderCompatDelegate
|
||||
{
|
||||
@available(iOS 17.0, *)
|
||||
@objc
|
||||
func prepareInterfaceToProvideCredentialCompat(for credentialRequest: ASCredentialRequestCompat)
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
@objc
|
||||
func provideCredentialWithoutUserInteractionCompat(for credentialRequest: ASCredentialRequestCompat)
|
||||
|
||||
@available(iOS 17.0, *)
|
||||
@objc
|
||||
func prepareInterfaceCompat(forPasskeyRegistration registrationRequest: ASCredentialRequestCompat)
|
||||
}
|
||||
|
||||
@objc(MyTest)
|
||||
public class MyTest : NSObject
|
||||
{
|
||||
var a: String
|
||||
|
||||
init(a: String) {
|
||||
self.a = a
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# ``iOS17CredentialProvider``
|
||||
|
||||
<!--@START_MENU_TOKEN@-->Summary<!--@END_MENU_TOKEN@-->
|
||||
|
||||
## Overview
|
||||
|
||||
<!--@START_MENU_TOKEN@-->Text<!--@END_MENU_TOKEN@-->
|
||||
|
||||
## Topics
|
||||
|
||||
### <!--@START_MENU_TOKEN@-->Group<!--@END_MENU_TOKEN@-->
|
||||
|
||||
- <!--@START_MENU_TOKEN@-->``Symbol``<!--@END_MENU_TOKEN@-->
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// iOS17CredentialProvider.h
|
||||
// iOS17CredentialProvider
|
||||
//
|
||||
// Created by Federico Maccaroni on 29/06/2023.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for iOS17CredentialProvider.
|
||||
FOUNDATION_EXPORT double iOS17CredentialProviderVersionNumber;
|
||||
|
||||
//! Project version string for iOS17CredentialProvider.
|
||||
FOUNDATION_EXPORT const unsigned char iOS17CredentialProviderVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <iOS17CredentialProvider/PublicHeader.h>
|
||||
|
||||
|
||||
Binary file not shown.
@@ -78,21 +78,20 @@
|
||||
<Version>1.9.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.5.1.1" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.14" />
|
||||
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.17" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.9.0.1" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0.15" />
|
||||
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.16" />
|
||||
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.19" />
|
||||
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.10.0" />
|
||||
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.3.1.1" />
|
||||
<PackageReference Include="Xamarin.Essentials">
|
||||
<Version>1.7.3</Version>
|
||||
<Version>1.7.5</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Firebase.Messaging">
|
||||
<Version>123.0.8</Version>
|
||||
<Version>123.1.1.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.6.1.1" />
|
||||
<PackageReference Include="Xamarin.Google.Dagger" Version="2.41.0.2" />
|
||||
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.8.0" />
|
||||
<PackageReference Include="Xamarin.Google.Dagger" Version="2.44.2.1" />
|
||||
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
|
||||
<Version>118.0.1.2</Version>
|
||||
<Version>118.0.1.3</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -160,6 +159,7 @@
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Effects\RemoveFontPaddingEffect.cs" />
|
||||
<Compile Include="Services\WatchDeviceService.cs" />
|
||||
<Compile Include="Renderers\CustomLabelRenderer.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidAsset Include="Assets\bwi-font.ttf" />
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Bit.Droid.Autofill
|
||||
private List<Field> _passwordFields = null;
|
||||
private List<Field> _usernameFields = null;
|
||||
private HashSet<string> _ignoreSearchTerms = new HashSet<string> { "search", "find", "recipient", "edit" };
|
||||
private HashSet<string> _usernameTerms = new HashSet<string> { "email", "phone", "username"};
|
||||
private HashSet<string> _usernameTerms = new HashSet<string> { "email", "phone", "username" };
|
||||
private HashSet<string> _passwordTerms = new HashSet<string> { "password", "pswd" };
|
||||
|
||||
public List<AutofillId> AutofillIds { get; private set; } = new List<AutofillId>();
|
||||
@@ -54,15 +54,14 @@ namespace Bit.Droid.Autofill
|
||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintPassword))
|
||||
{
|
||||
_passwordFields.AddRange(HintToFieldsMap[View.AutofillHintPassword]);
|
||||
return _passwordFields;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
_passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
|
||||
if (!_passwordFields.Any())
|
||||
{
|
||||
_passwordFields = Fields.Where(f => FieldIsPassword(f)).ToList();
|
||||
if (!_passwordFields.Any())
|
||||
{
|
||||
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
|
||||
}
|
||||
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
|
||||
}
|
||||
return _passwordFields;
|
||||
}
|
||||
@@ -87,24 +86,26 @@ namespace Bit.Droid.Autofill
|
||||
{
|
||||
_usernameFields.AddRange(HintToFieldsMap[View.AutofillHintUsername]);
|
||||
}
|
||||
if (_usernameFields.Any())
|
||||
{
|
||||
return _usernameFields;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var passwordField in PasswordFields)
|
||||
{
|
||||
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId)
|
||||
.LastOrDefault();
|
||||
if (usernameField != null)
|
||||
{
|
||||
_usernameFields.Add(usernameField);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_usernameFields.Any())
|
||||
foreach (var passwordField in PasswordFields)
|
||||
{
|
||||
var usernameField = Fields.TakeWhile(f => f.AutofillId != passwordField.AutofillId)
|
||||
.LastOrDefault();
|
||||
if (usernameField != null)
|
||||
{
|
||||
_usernameFields = Fields.Where(f => FieldIsUsername(f)).ToList();
|
||||
_usernameFields.Add(usernameField);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_usernameFields.Any())
|
||||
{
|
||||
_usernameFields = Fields.Where(f => FieldIsUsername(f)).ToList();
|
||||
}
|
||||
return _usernameFields;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using Bit.App.Utilities;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Utilities.AccountManagement;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Enums;
|
||||
#if !FDROID
|
||||
using Android.Gms.Security;
|
||||
#endif
|
||||
@@ -147,7 +148,7 @@ namespace Bit.Droid
|
||||
var storageMediatorService = new StorageMediatorService(mobileStorageService, secureStorageService, preferencesStorage);
|
||||
var stateService = new StateService(mobileStorageService, secureStorageService, storageMediatorService, messagingService);
|
||||
var stateMigrationService =
|
||||
new StateMigrationService(liteDbStorage, preferencesStorage, secureStorageService);
|
||||
new StateMigrationService(DeviceType.Android, liteDbStorage, preferencesStorage, secureStorageService);
|
||||
var clipboardService = new ClipboardService(stateService);
|
||||
var deviceActionService = new DeviceActionService(stateService, messagingService);
|
||||
var fileService = new FileService(stateService, broadcasterService);
|
||||
@@ -155,7 +156,7 @@ namespace Bit.Droid
|
||||
messagingService, broadcasterService);
|
||||
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
|
||||
platformUtilsService, new LazyResolve<IEventService>());
|
||||
var biometricService = new BiometricService();
|
||||
var biometricService = new BiometricService(stateService);
|
||||
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
|
||||
var cryptoService = new CryptoService(stateService, cryptoFunctionService);
|
||||
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2023.3.3" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2023.5.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
|
||||
31
src/Android/Renderers/CustomLabelRenderer.cs
Normal file
31
src/Android/Renderers/CustomLabelRenderer.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using System.ComponentModel;
|
||||
using Xamarin.Forms.Platform.Android;
|
||||
using Android.Content;
|
||||
using Xamarin.Forms;
|
||||
using Bit.Droid.Renderers;
|
||||
|
||||
[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
|
||||
namespace Bit.Droid.Renderers
|
||||
{
|
||||
public class CustomLabelRenderer : LabelRenderer
|
||||
{
|
||||
public CustomLabelRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var label = sender as CustomLabel;
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(CustomLabel.AutomationId):
|
||||
Control.ContentDescription = label.AutomationId;
|
||||
break;
|
||||
}
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using Android.OS;
|
||||
using Android.Security.Keystore;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Java.Security;
|
||||
using Javax.Crypto;
|
||||
|
||||
@@ -12,6 +11,8 @@ namespace Bit.Droid.Services
|
||||
{
|
||||
public class BiometricService : IBiometricService
|
||||
{
|
||||
private readonly IStateService _stateService;
|
||||
|
||||
private const string KeyName = "com.8bit.bitwarden.biometric_integrity";
|
||||
|
||||
private const string KeyStoreName = "AndroidKeyStore";
|
||||
@@ -23,28 +24,28 @@ namespace Bit.Droid.Services
|
||||
|
||||
private readonly KeyStore _keystore;
|
||||
|
||||
public BiometricService()
|
||||
public BiometricService(IStateService stateService)
|
||||
{
|
||||
_stateService = stateService;
|
||||
_keystore = KeyStore.GetInstance(KeyStoreName);
|
||||
_keystore.Load(null);
|
||||
}
|
||||
|
||||
public Task<bool> SetupBiometricAsync(string bioIntegrityKey = null)
|
||||
public async Task<bool> SetupBiometricAsync(string bioIntegritySrcKey = null)
|
||||
{
|
||||
// bioIntegrityKey used in iOS only
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
|
||||
{
|
||||
CreateKey();
|
||||
await CreateKeyAsync(bioIntegritySrcKey);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public Task<bool> ValidateIntegrityAsync(string bioIntegrityKey = null)
|
||||
public async Task<bool> IsSystemBiometricIntegrityValidAsync(string bioIntegritySrcKey = null)
|
||||
{
|
||||
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
@@ -55,7 +56,7 @@ namespace Bit.Droid.Services
|
||||
|
||||
if (key == null || cipher == null)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
cipher.Init(CipherMode.EncryptMode, key);
|
||||
@@ -63,25 +64,32 @@ namespace Bit.Droid.Services
|
||||
catch (KeyPermanentlyInvalidatedException e)
|
||||
{
|
||||
// Biometric has changed
|
||||
return Task.FromResult(false);
|
||||
await ClearStateAsync(bioIntegritySrcKey);
|
||||
return false;
|
||||
}
|
||||
catch (UnrecoverableKeyException e)
|
||||
{
|
||||
// Biometric was disabled and re-enabled
|
||||
return Task.FromResult(false);
|
||||
await ClearStateAsync(bioIntegritySrcKey);
|
||||
return false;
|
||||
}
|
||||
catch (InvalidKeyException e)
|
||||
{
|
||||
// Fallback for old bitwarden users without a key
|
||||
LoggerHelper.LogEvenIfCantBeResolved(e);
|
||||
CreateKey();
|
||||
await CreateKeyAsync(bioIntegritySrcKey);
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CreateKey()
|
||||
private async Task CreateKeyAsync(string bioIntegritySrcKey = null)
|
||||
{
|
||||
bioIntegritySrcKey ??= Core.Constants.BiometricIntegritySourceKey;
|
||||
await _stateService.SetSystemBiometricIntegrityState(bioIntegritySrcKey,
|
||||
await GetStateAsync(bioIntegritySrcKey));
|
||||
await _stateService.SetAccountBiometricIntegrityValidAsync(bioIntegritySrcKey);
|
||||
|
||||
try
|
||||
{
|
||||
var keyGen = KeyGenerator.GetInstance(KeyAlgorithm, KeyStoreName);
|
||||
@@ -101,5 +109,16 @@ namespace Bit.Droid.Services
|
||||
LoggerHelper.LogEvenIfCantBeResolved(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> GetStateAsync(string bioIntegritySrcKey)
|
||||
{
|
||||
return await _stateService.GetSystemBiometricIntegrityState(bioIntegritySrcKey) ??
|
||||
Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
private async Task ClearStateAsync(string bioIntegritySrcKey)
|
||||
{
|
||||
await _stateService.SetSystemBiometricIntegrityState(bioIntegritySrcKey, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
|
||||
<PackageReference Include="SkiaSharp.Views.Forms" Version="2.88.2" />
|
||||
<PackageReference Include="Xamarin.CommunityToolkit" Version="2.0.5" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.3" />
|
||||
<PackageReference Include="SkiaSharp.Views.Forms" Version="2.88.3" />
|
||||
<PackageReference Include="Xamarin.CommunityToolkit" Version="2.0.6" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
|
||||
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2515" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2578" />
|
||||
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
|
||||
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
|
||||
<PackageReference Include="MessagePack" Version="2.4.59" />
|
||||
@@ -145,6 +145,7 @@
|
||||
<Folder Include="Controls\DateTime\" />
|
||||
<Folder Include="Controls\IconLabelButton\" />
|
||||
<Folder Include="Controls\PasswordStrengthProgressBar\" />
|
||||
<Folder Include="Utilities\Automation\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -440,5 +441,6 @@
|
||||
<None Remove="MessagePack" />
|
||||
<None Remove="MessagePack.MSBuild.Tasks" />
|
||||
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
||||
<None Remove="Utilities\Automation\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace Bit.App
|
||||
private readonly IFileService _fileService;
|
||||
private readonly IAccountsManager _accountsManager;
|
||||
private readonly IPushNotificationService _pushNotificationService;
|
||||
private readonly IConfigService _configService;
|
||||
private static bool _isResumed;
|
||||
// these variables are static because the app is launching new activities on notification click, creating new instances of App.
|
||||
private static bool _pendingCheckPasswordlessLoginRequests;
|
||||
@@ -61,6 +62,7 @@ namespace Bit.App
|
||||
_fileService = ServiceContainer.Resolve<IFileService>();
|
||||
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
|
||||
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
||||
_configService = ServiceContainer.Resolve<IConfigService>();
|
||||
|
||||
_accountsManager.Init(() => Options, this);
|
||||
|
||||
@@ -161,6 +163,18 @@ namespace Bit.App
|
||||
new NavigationPage(new RemoveMasterPasswordPage()));
|
||||
});
|
||||
}
|
||||
else if (message.Command == Constants.ForceUpdatePassword)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(async () =>
|
||||
{
|
||||
await Application.Current.MainPage.Navigation.PushModalAsync(
|
||||
new NavigationPage(new UpdateTempPasswordPage()));
|
||||
});
|
||||
}
|
||||
else if (message.Command == "syncCompleted")
|
||||
{
|
||||
await _configService.GetAsync(true);
|
||||
}
|
||||
else if (message.Command == Constants.PasswordlessLoginRequestKey
|
||||
|| message.Command == "unlocked"
|
||||
|| message.Command == AccountsManagerMessageCommands.ACCOUNT_SWITCH_COMPLETED)
|
||||
@@ -285,6 +299,8 @@ namespace Bit.App
|
||||
// Reset delay on every start
|
||||
_vaultTimeoutService.DelayLockAndLogoutMs = null;
|
||||
}
|
||||
|
||||
await _configService.GetAsync();
|
||||
_messagingService.Send("startEventTimer");
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,15 @@
|
||||
BackgroundColor="{DynamicResource BackgroundColor}"
|
||||
VerticalOptions="Start"
|
||||
RowHeight="{Binding AccountListRowHeight, Source={x:Reference _mainOverlay}}"
|
||||
effects:ScrollViewContentInsetAdjustmentBehaviorEffect.ContentInsetAdjustmentBehavior="Never">
|
||||
effects:ScrollViewContentInsetAdjustmentBehaviorEffect.ContentInsetAdjustmentBehavior="Never"
|
||||
AutomationId="AccountListView">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="view:AccountView">
|
||||
<controls:AccountViewCell
|
||||
Account="{Binding .}"
|
||||
SelectAccountCommand="{Binding SelectAccountCommand, Source={x:Reference _mainOverlay}}"
|
||||
LongPressAccountCommand="{Binding LongPressAccountCommand, Source={x:Reference _mainOverlay}}"
|
||||
AutomationId="AccountViewCell"
|
||||
/>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
|
||||
@@ -60,20 +60,23 @@
|
||||
Text="{Binding AccountView.Email}"
|
||||
IsVisible="{Binding IsActive}"
|
||||
StyleClass="accountlist-title, accountlist-title-platform"
|
||||
LineBreakMode="TailTruncation" />
|
||||
LineBreakMode="TailTruncation"
|
||||
AutomationId="AccountEmailLabel" />
|
||||
<Label
|
||||
Grid.Row="0"
|
||||
Text="{Binding AccountView.Email}"
|
||||
IsVisible="{Binding IsActive, Converter={StaticResource inverseBool}}"
|
||||
StyleClass="accountlist-title, accountlist-title-platform"
|
||||
TextColor="{DynamicResource MutedColor}"
|
||||
LineBreakMode="TailTruncation" />
|
||||
LineBreakMode="TailTruncation"
|
||||
AutomationId="AccountEmailLabel" />
|
||||
<Label
|
||||
Grid.Row="1"
|
||||
IsVisible="{Binding ShowHostname}"
|
||||
Text="{Binding AccountView.Hostname}"
|
||||
StyleClass="accountlist-sub, accountlist-sub-platform"
|
||||
LineBreakMode="TailTruncation" />
|
||||
LineBreakMode="TailTruncation"
|
||||
AutomationId="AccountHostUrlLabel" />
|
||||
<Label
|
||||
Grid.Row="2"
|
||||
Text="{u:I18n AccountUnlocked}"
|
||||
@@ -81,7 +84,8 @@
|
||||
StyleClass="accountlist-sub, accountlist-sub-platform"
|
||||
FontAttributes="Italic"
|
||||
TextTransform="Lowercase"
|
||||
LineBreakMode="TailTruncation" />
|
||||
LineBreakMode="TailTruncation"
|
||||
AutomationId="AccountStatusLabel" />
|
||||
<Label
|
||||
Grid.Row="2"
|
||||
Text="{u:I18n AccountLocked}"
|
||||
@@ -89,7 +93,8 @@
|
||||
StyleClass="accountlist-sub, accountlist-sub-platform"
|
||||
FontAttributes="Italic"
|
||||
TextTransform="Lowercase"
|
||||
LineBreakMode="TailTruncation" />
|
||||
LineBreakMode="TailTruncation"
|
||||
AutomationId="AccountStatusLabel" />
|
||||
<Label
|
||||
Grid.Row="2"
|
||||
Text="{u:I18n AccountLoggedOut}"
|
||||
@@ -97,7 +102,8 @@
|
||||
StyleClass="accountlist-sub, accountlist-sub-platform"
|
||||
FontAttributes="Italic"
|
||||
TextTransform="Lowercase"
|
||||
LineBreakMode="TailTruncation" />
|
||||
LineBreakMode="TailTruncation"
|
||||
AutomationId="AccountStatusLabel" />
|
||||
</Grid>
|
||||
|
||||
<controls:IconLabel
|
||||
@@ -107,7 +113,8 @@
|
||||
Margin="12,0"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform" />
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
AutomationId="InactiveVaultIcon" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="2"
|
||||
Text="{Binding AuthStatusIconActive}"
|
||||
@@ -116,7 +123,8 @@
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center"
|
||||
StyleClass="list-icon, list-icon-platform"
|
||||
TextColor="{DynamicResource TextColor}"/>
|
||||
TextColor="{DynamicResource TextColor}"
|
||||
AutomationId="ActiveVaultIcon" />
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
@@ -147,7 +155,8 @@
|
||||
StyleClass="accountlist-title, accountlist-title-platform"
|
||||
LineBreakMode="TailTruncation"
|
||||
VerticalOptions="Center"
|
||||
Grid.Column="1" />
|
||||
Grid.Column="1"
|
||||
AutomationId="AddAccountButton" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ViewCell>
|
||||
@@ -9,7 +9,8 @@
|
||||
StyleClass="list-row, list-row-platform"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="0"
|
||||
x:DataType="controls:CipherViewCellViewModel">
|
||||
x:DataType="controls:CipherViewCellViewModel"
|
||||
AutomationId="CipherCell">
|
||||
|
||||
<Grid.Resources>
|
||||
<u:IconGlyphConverter x:Key="iconGlyphConverter"/>
|
||||
@@ -36,7 +37,8 @@
|
||||
IsVisible="{Binding ShowIconImage, Converter={StaticResource inverseBool}}"
|
||||
Text="{Binding Cipher, Converter={StaticResource iconGlyphConverter}}"
|
||||
ShouldUpdateFontSizeDynamicallyForAccesibility="True"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
AutomationProperties.IsInAccessibleTree="False"
|
||||
AutomationId="CipherTypeIcon" />
|
||||
|
||||
<ff:CachedImage
|
||||
x:Name="_iconImage"
|
||||
@@ -52,7 +54,8 @@
|
||||
Aspect="AspectFit"
|
||||
IsVisible="{Binding ShowIconImage}"
|
||||
Source="{Binding IconImageSource, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="False" />
|
||||
AutomationProperties.IsInAccessibleTree="False"
|
||||
AutomationId="CipherWebsiteIcon" />
|
||||
|
||||
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center" Padding="0, 7">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -71,7 +74,8 @@
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Cipher.Name}" />
|
||||
Text="{Binding Cipher.Name}"
|
||||
AutomationId="CipherNameLabel" />
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
@@ -80,7 +84,8 @@
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Cipher.SubTitle}"
|
||||
IsVisible="{Binding Source={RelativeSource Self}, Path=Text,
|
||||
Converter={StaticResource stringHasValueConverter}}"/>
|
||||
Converter={StaticResource stringHasValueConverter}}"
|
||||
AutomationId="CipherSubTitleLabel" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
@@ -91,7 +96,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Collection}}"
|
||||
IsVisible="{Binding Cipher.Shared, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Shared}" />
|
||||
AutomationProperties.Name="{u:I18n Shared}"
|
||||
AutomationId="CipherInCollectionIcon" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="2"
|
||||
Grid.Row="0"
|
||||
@@ -102,7 +108,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Paperclip}}"
|
||||
IsVisible="{Binding Cipher.HasAttachments, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Attachments}" />
|
||||
AutomationProperties.Name="{u:I18n Attachments}"
|
||||
AutomationId="CipherWithAttachmentsIcon" />
|
||||
</Grid>
|
||||
|
||||
<controls:MiButton
|
||||
@@ -114,6 +121,7 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="EndAndExpand"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
AutomationId="CipherOptionsButton" />
|
||||
|
||||
</controls:ExtendedGrid>
|
||||
13
src/App/Controls/CustomLabel.cs
Normal file
13
src/App/Controls/CustomLabel.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class CustomLabel : Label
|
||||
{
|
||||
public CustomLabel()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Controls.SendViewCell"
|
||||
@@ -54,14 +54,16 @@
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Send.Name}" />
|
||||
Text="{Binding Send.Name}"
|
||||
AutomationId="SendNameLabel" />
|
||||
<Label
|
||||
LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Grid.ColumnSpan="6"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Send.DisplayDate}" />
|
||||
Text="{Binding Send.DisplayDate}"
|
||||
AutomationId="SendDateLabel" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="1"
|
||||
Grid.Row="0"
|
||||
@@ -72,7 +74,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.ExclamationTriangle}}"
|
||||
IsVisible="{Binding Send.Disabled, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Disabled}" />
|
||||
AutomationProperties.Name="{u:I18n Disabled}"
|
||||
AutomationId="DisabledSendLabel" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="2"
|
||||
Grid.Row="0"
|
||||
@@ -83,7 +86,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Key}}"
|
||||
IsVisible="{Binding Send.HasPassword, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Password}" />
|
||||
AutomationProperties.Name="{u:I18n Password}"
|
||||
AutomationId="PasswordProtectedSendLabel" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="3"
|
||||
Grid.Row="0"
|
||||
@@ -94,7 +98,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Ban}}"
|
||||
IsVisible="{Binding Send.MaxAccessCountReached, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n MaxAccessCountReached}" />
|
||||
AutomationProperties.Name="{u:I18n MaxAccessCountReached}"
|
||||
AutomationId="SendMaxAccessCountReachedLabel" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="4"
|
||||
Grid.Row="0"
|
||||
@@ -105,7 +110,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clock}}"
|
||||
IsVisible="{Binding Send.Expired, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Expired}" />
|
||||
AutomationProperties.Name="{u:I18n Expired}"
|
||||
AutomationId="ExpiredSendLabel" />
|
||||
<controls:IconLabel
|
||||
Grid.Column="5"
|
||||
Grid.Row="0"
|
||||
@@ -116,7 +122,8 @@
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
|
||||
IsVisible="{Binding Send.PendingDelete, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n PendingDelete}" />
|
||||
AutomationProperties.Name="{u:I18n PendingDelete}"
|
||||
AutomationId="SendWithPendingDeletionLabel" />
|
||||
</Grid>
|
||||
|
||||
<controls:MiButton
|
||||
@@ -129,6 +136,7 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="EndAndExpand"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
AutomationId="SendOptionsButton" />
|
||||
|
||||
</controls:ExtendedGrid>
|
||||
|
||||
@@ -33,7 +33,8 @@
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="BooleanCustomFieldNameLabel" />
|
||||
<Label
|
||||
Text="{Binding Field.Name, Mode=OneWay}"
|
||||
IsVisible="{Binding IsEditing}"
|
||||
@@ -49,13 +50,15 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="0, 5, 0, 0"
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="BooleanCustomFieldValueLabel" />
|
||||
<Switch
|
||||
IsToggled="{Binding BooleanValue}"
|
||||
IsVisible="{Binding IsEditing}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2" />
|
||||
Grid.RowSpan="2"
|
||||
AutomationId="BooleanCustomFieldValueToggle" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
Text="{Binding Field.Name, Mode=OneWay}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="HiddenCustomFieldNameLabel" />
|
||||
<StackLayout
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
@@ -39,7 +40,8 @@
|
||||
<controls:MonoLabel
|
||||
Text="{Binding ValueText, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
IsVisible="{Binding ShowHiddenValue}" />
|
||||
IsVisible="{Binding ShowHiddenValue}"
|
||||
AutomationId="HiddenCustomFieldValueLabel" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Field.MaskedValue, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
@@ -54,7 +56,10 @@
|
||||
IsPassword="{Binding ShowHiddenValue, Converter={StaticResource inverseBool}}"
|
||||
IsEnabled="{Binding ShowViewHidden}"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False">
|
||||
IsTextPredictionEnabled="False"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{Binding Field.Name}"
|
||||
AutomationId="HiddenCustomFieldValueEntry">
|
||||
<Entry.Keyboard>
|
||||
<Keyboard x:FactoryMethod="Create">
|
||||
<x:Arguments>
|
||||
@@ -72,7 +77,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationId="HiddenCustomFieldShowValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
|
||||
@@ -29,13 +29,15 @@
|
||||
Text="{Binding Field.Name, Mode=OneWay}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="LinkedCustomFieldNameLabel" />
|
||||
<controls:IconLabel
|
||||
Text="{Binding ValueText, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="LinkedCustomFieldValueLabel" />
|
||||
<StackLayout
|
||||
StyleClass="box-row, box-row-input"
|
||||
IsVisible="{Binding IsEditing}">
|
||||
@@ -44,7 +46,8 @@
|
||||
ItemsSource="{Binding LinkedFieldOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding LinkedFieldOptionSelectedIndex}"
|
||||
ItemDisplayBinding="{Binding Key}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="LinkedCustomFieldValuePicker" />
|
||||
</StackLayout>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
@@ -55,7 +58,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
AutomationId="LinkedCustomFieldOptionsButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator" IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
|
||||
</StackLayout>
|
||||
|
||||
@@ -29,19 +29,24 @@
|
||||
Text="{Binding Field.Name, Mode=OneWay}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="TextCustomFieldNameLabel" />
|
||||
<Label
|
||||
Text="{Binding ValueText, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="TextCustomFieldValueLabel" />
|
||||
<Entry
|
||||
Text="{Binding Field.Value}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding IsEditing}" />
|
||||
IsVisible="{Binding IsEditing}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{Binding Field.Name}"
|
||||
AutomationId="TextCustomFieldValueEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -51,7 +56,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Copy}" />
|
||||
AutomationProperties.Name="{u:I18n Copy}"
|
||||
AutomationId="TextCustomFieldCopyValue" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
|
||||
@@ -61,7 +67,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
AutomationId="TextCustomFieldOptionsButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator" IsVisible="{Binding IsEditing, Mode=OneWay, Converter={StaticResource inverseBool}}" />
|
||||
</StackLayout>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.Domain;
|
||||
@@ -73,13 +70,13 @@ namespace Bit.App.Pages
|
||||
set => SetProperty(ref _policy, value);
|
||||
}
|
||||
|
||||
public string ShowPasswordIcon => ShowPassword ? "" : "";
|
||||
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
|
||||
public string PasswordVisibilityAccessibilityText => ShowPassword ? AppResources.PasswordIsVisibleTapToHide : AppResources.PasswordIsNotVisibleTapToShow;
|
||||
public string MasterPassword { get; set; }
|
||||
public string ConfirmMasterPassword { get; set; }
|
||||
public string Hint { get; set; }
|
||||
|
||||
public async Task InitAsync(bool forceSync = false)
|
||||
public virtual async Task InitAsync(bool forceSync = false)
|
||||
{
|
||||
if (forceSync)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
Placeholder="ex. https://bitwarden.company.com"
|
||||
StyleClass="box-value"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="ServerUrlEntry"/>
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n SelfHostedEnvironmentFooter}"
|
||||
@@ -53,7 +54,8 @@
|
||||
x:Name="_webVaultEntry"
|
||||
Text="{Binding WebVaultUrl}"
|
||||
Keyboard="Url"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="WebVaultUrlEntry"/>
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row">
|
||||
<Label
|
||||
@@ -63,7 +65,8 @@
|
||||
x:Name="_apiEntry"
|
||||
Text="{Binding ApiUrl}"
|
||||
Keyboard="Url"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ApiUrlEntry"/>
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row">
|
||||
<Label
|
||||
@@ -73,7 +76,8 @@
|
||||
x:Name="_identityEntry"
|
||||
Text="{Binding IdentityUrl}"
|
||||
Keyboard="Url"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityUrlEntry"/>
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row">
|
||||
<Label
|
||||
@@ -85,7 +89,8 @@
|
||||
Keyboard="Url"
|
||||
StyleClass="box-value"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="IconsUrlEntry"/>
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n CustomEnvironmentFooter}"
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.CommunityToolkit.ObjectModel;
|
||||
|
||||
@@ -18,7 +19,8 @@ namespace Bit.App.Pages
|
||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
|
||||
|
||||
PageTitle = AppResources.Settings;
|
||||
BaseUrl = _environmentService.BaseUrl;
|
||||
BaseUrl = _environmentService.BaseUrl == EnvironmentUrlData.DefaultEU.Base || EnvironmentUrlData.DefaultUS.Base == _environmentService.BaseUrl ?
|
||||
string.Empty : _environmentService.BaseUrl;
|
||||
WebVaultUrl = _environmentService.WebVaultUrl;
|
||||
ApiUrl = _environmentService.ApiUrl;
|
||||
IdentityUrl = _environmentService.IdentityUrl;
|
||||
|
||||
@@ -23,12 +23,9 @@
|
||||
Priority="-1"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"
|
||||
AutomationId="AccountIconButton" />
|
||||
<ToolbarItem x:Name="_closeButton" Text="{u:I18n Close}" Command="{Binding CloseCommand}" Order="Primary" Priority="-1"/>
|
||||
<ToolbarItem
|
||||
Icon="cog_environment.png" Clicked="Environment_Clicked" Order="Primary"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<ContentPage.Resources>
|
||||
@@ -53,7 +50,9 @@
|
||||
Keyboard="Email"
|
||||
StyleClass="box-value"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding ContinueCommand}">
|
||||
ReturnCommand="{Binding ContinueCommand}"
|
||||
AutomationId="EmailAddressEntry"
|
||||
>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Disabled">
|
||||
@@ -66,7 +65,28 @@
|
||||
</Entry>
|
||||
<StackLayout
|
||||
Orientation="Horizontal"
|
||||
Margin="0, 16, 0 ,0">
|
||||
Margin="0, 6, 0 ,0">
|
||||
<StackLayout.GestureRecognizers>
|
||||
<TapGestureRecognizer
|
||||
Command="{Binding ShowEnvironmentPickerCommand}" />
|
||||
</StackLayout.GestureRecognizers>
|
||||
<Label
|
||||
Text="{Binding RegionText}"
|
||||
FontSize="13"
|
||||
TextColor="{DynamicResource MutedColor}"
|
||||
VerticalOptions="Center"
|
||||
VerticalTextAlignment="Center"/>
|
||||
<controls:IconLabel
|
||||
Text="{Binding SelectedEnvironmentName}"
|
||||
FontSize="13"
|
||||
TextColor="{DynamicResource PrimaryColor}"
|
||||
VerticalOptions="Center"
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="RegionSelectorDropdown"/>
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
Orientation="Horizontal"
|
||||
Margin="0, 20, 0 ,0">
|
||||
<StackLayout.GestureRecognizers>
|
||||
<TapGestureRecognizer
|
||||
Command="{Binding RememberEmailCommand}" />
|
||||
@@ -76,21 +96,27 @@
|
||||
StyleClass="text-sm"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="Center"
|
||||
VerticalTextAlignment="Center"/>
|
||||
VerticalTextAlignment="Center"
|
||||
/>
|
||||
<Switch
|
||||
Scale="0.8"
|
||||
IsToggled="{Binding RememberEmail}"
|
||||
VerticalOptions="Center"/>
|
||||
VerticalOptions="Center"
|
||||
AutomationId="RememberMeSwitch"
|
||||
/>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
<Button Text="{u:I18n Continue}"
|
||||
StyleClass="btn-primary"
|
||||
IsEnabled="{Binding CanContinue}"
|
||||
Command="{Binding ContinueCommand}" />
|
||||
Command="{Binding ContinueCommand}"
|
||||
AutomationId="ContinueButton"
|
||||
/>
|
||||
|
||||
<Label FormattedText="{Binding CreateAccountText}"
|
||||
Margin="0, 10"
|
||||
StyleClass="box-footer-label">
|
||||
StyleClass="box-footer-label"
|
||||
AutomationId="CreateAccountLabel">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding CreateAccountCommand}" />
|
||||
</Label.GestureRecognizers>
|
||||
@@ -116,5 +142,4 @@
|
||||
MainPage="{Binding Source={x:Reference _page}}"
|
||||
BindingContext="{Binding AccountSwitchingOverlayViewModel}"/>
|
||||
</AbsoluteLayout>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Bit.App.Pages
|
||||
private readonly AppOptions _appOptions;
|
||||
private IBroadcasterService _broadcasterService;
|
||||
|
||||
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
||||
|
||||
public HomePage(AppOptions appOptions = null)
|
||||
{
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
@@ -70,6 +72,14 @@ namespace Bit.App.Pages
|
||||
});
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
await _vm.UpdateEnvironment();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Value?.Exception(ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnBackButtonPressed()
|
||||
@@ -128,14 +138,6 @@ namespace Bit.App.Pages
|
||||
await Navigation.PushModalAsync(new NavigationPage(page));
|
||||
}
|
||||
|
||||
private void Environment_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (DoOnce())
|
||||
{
|
||||
_vm.StartEnvironmentAction();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StartEnvironmentAsync()
|
||||
{
|
||||
await _accountListOverlay.HideAsync();
|
||||
|
||||
@@ -4,7 +4,10 @@ using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Response;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.CommunityToolkit.ObjectModel;
|
||||
@@ -17,16 +20,19 @@ namespace Bit.App.Pages
|
||||
{
|
||||
private readonly IStateService _stateService;
|
||||
private readonly IMessagingService _messagingService;
|
||||
private readonly IPlatformUtilsService _platformUtilsService;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IEnvironmentService _environmentService;
|
||||
private readonly IAccountsManager _accountManager;
|
||||
private readonly IConfigService _configService;
|
||||
|
||||
private bool _showCancelButton;
|
||||
private bool _rememberEmail;
|
||||
private string _email;
|
||||
private string _selectedEnvironmentName;
|
||||
private bool _isEmailEnabled;
|
||||
private bool _canLogin;
|
||||
private IPlatformUtilsService _platformUtilsService;
|
||||
private ILogger _logger;
|
||||
private IEnvironmentService _environmentService;
|
||||
private IAccountsManager _accountManager;
|
||||
private bool _displayEuEnvironment;
|
||||
|
||||
public HomeViewModel()
|
||||
{
|
||||
@@ -36,6 +42,7 @@ namespace Bit.App.Pages
|
||||
_logger = ServiceContainer.Resolve<ILogger>();
|
||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
||||
_accountManager = ServiceContainer.Resolve<IAccountsManager>();
|
||||
_configService = ServiceContainer.Resolve<IConfigService>();
|
||||
|
||||
PageTitle = AppResources.Bitwarden;
|
||||
|
||||
@@ -49,6 +56,8 @@ namespace Bit.App.Pages
|
||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
CloseCommand = new AsyncCommand(async () => await Device.InvokeOnMainThreadAsync(CloseAction),
|
||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
ShowEnvironmentPickerCommand = new AsyncCommand(ShowEnvironmentPickerAsync,
|
||||
onException: _logger.Exception, allowsMultipleExecutions: false);
|
||||
InitAsync().FireAndForget();
|
||||
}
|
||||
|
||||
@@ -71,6 +80,13 @@ namespace Bit.App.Pages
|
||||
additionalPropertyNames: new[] { nameof(CanContinue) });
|
||||
}
|
||||
|
||||
public string SelectedEnvironmentName
|
||||
{
|
||||
get => $"{_selectedEnvironmentName} {BitwardenIcons.AngleDown}";
|
||||
set => SetProperty(ref _selectedEnvironmentName, value);
|
||||
}
|
||||
|
||||
public string RegionText => $"{AppResources.Region}:";
|
||||
public bool CanContinue => !string.IsNullOrEmpty(Email);
|
||||
|
||||
public FormattedString CreateAccountText
|
||||
@@ -101,11 +117,13 @@ namespace Bit.App.Pages
|
||||
public AsyncCommand ContinueCommand { get; }
|
||||
public AsyncCommand CloseCommand { get; }
|
||||
public AsyncCommand CreateAccountCommand { get; }
|
||||
public AsyncCommand ShowEnvironmentPickerCommand { get; }
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
Email = await _stateService.GetRememberedEmailAsync();
|
||||
RememberEmail = !string.IsNullOrEmpty(Email);
|
||||
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag, forceRefresh: true);
|
||||
}
|
||||
|
||||
public async Task ContinueToLoginStepAsync()
|
||||
@@ -144,5 +162,59 @@ namespace Bit.App.Pages
|
||||
await _platformUtilsService.ShowDialogAsync(AppResources.GenericErrorMessage, AppResources.AnErrorHasOccurred, AppResources.Ok);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ShowEnvironmentPickerAsync()
|
||||
{
|
||||
_displayEuEnvironment = await _configService.GetFeatureFlagBoolAsync(Constants.DisplayEuEnvironmentFlag);
|
||||
var options = _displayEuEnvironment
|
||||
? new string[] { AppResources.US, AppResources.EU, AppResources.SelfHosted }
|
||||
: new string[] { AppResources.US, AppResources.SelfHosted };
|
||||
|
||||
await Device.InvokeOnMainThreadAsync(async () =>
|
||||
{
|
||||
var result = await Page.DisplayActionSheet(AppResources.DataRegion, AppResources.Cancel, null, options);
|
||||
|
||||
if (result is null || result == AppResources.Cancel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == AppResources.SelfHosted)
|
||||
{
|
||||
StartEnvironmentAction?.Invoke();
|
||||
return;
|
||||
}
|
||||
|
||||
await _environmentService.SetUrlsAsync(result == AppResources.EU ? EnvironmentUrlData.DefaultEU : EnvironmentUrlData.DefaultUS);
|
||||
await _configService.GetAsync(true);
|
||||
SelectedEnvironmentName = result;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task UpdateEnvironment()
|
||||
{
|
||||
var environmentsSaved = await _stateService.GetPreAuthEnvironmentUrlsAsync();
|
||||
if (environmentsSaved == null || environmentsSaved.IsEmpty)
|
||||
{
|
||||
await _environmentService.SetUrlsAsync(EnvironmentUrlData.DefaultUS);
|
||||
environmentsSaved = EnvironmentUrlData.DefaultUS;
|
||||
SelectedEnvironmentName = AppResources.US;
|
||||
return;
|
||||
}
|
||||
|
||||
if (environmentsSaved.Base == EnvironmentUrlData.DefaultUS.Base)
|
||||
{
|
||||
SelectedEnvironmentName = AppResources.US;
|
||||
}
|
||||
else if (environmentsSaved.Base == EnvironmentUrlData.DefaultEU.Base)
|
||||
{
|
||||
SelectedEnvironmentName = AppResources.EU;
|
||||
}
|
||||
else
|
||||
{
|
||||
await _configService.GetAsync(true);
|
||||
SelectedEnvironmentName = AppResources.SelfHosted;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
Priority="-1"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"
|
||||
AutomationId="AccountIconButton" />
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<ContentPage.Resources>
|
||||
@@ -71,7 +72,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="PinEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -81,7 +83,8 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"/>
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
|
||||
AutomationId="PinVisibilityToggle" />
|
||||
</Grid>
|
||||
<Grid
|
||||
x:Name="_passwordGrid"
|
||||
@@ -111,7 +114,8 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="MasterPasswordEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -121,7 +125,9 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}" />
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
|
||||
AutomationId="PasswordVisibilityToggle"
|
||||
/>
|
||||
</Grid>
|
||||
<StackLayout
|
||||
StyleClass="box-row"
|
||||
@@ -137,7 +143,7 @@
|
||||
</StackLayout>
|
||||
<StackLayout Padding="10, 0">
|
||||
<Label
|
||||
Text="{u:I18n BiometricInvalidated}"
|
||||
Text="{u:I18n AccountBiometricInvalidated}"
|
||||
StyleClass="box-footer-label,text-danger,text-bold"
|
||||
IsVisible="{Binding BiometricIntegrityValid, Converter={StaticResource inverseBool}}" />
|
||||
<Button Text="{Binding BiometricButtonText}" Clicked="Biometric_Clicked"
|
||||
@@ -147,7 +153,8 @@
|
||||
x:Name="_unlockButton"
|
||||
Text="{u:I18n Unlock}"
|
||||
StyleClass="btn-primary"
|
||||
Clicked="Unlock_Clicked" />
|
||||
Clicked="Unlock_Clicked"
|
||||
AutomationId="UnlockVaultButton" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -31,6 +31,8 @@ namespace Bit.App.Pages
|
||||
private readonly ILogger _logger;
|
||||
private readonly IWatchDeviceService _watchDeviceService;
|
||||
private readonly WeakEventManager<int?> _secretEntryFocusWeakEventManager = new WeakEventManager<int?>();
|
||||
private readonly IPolicyService _policyService;
|
||||
private readonly IPasswordGenerationService _passwordGenerationService;
|
||||
|
||||
private string _email;
|
||||
private string _masterPassword;
|
||||
@@ -61,6 +63,8 @@ namespace Bit.App.Pages
|
||||
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
||||
_logger = ServiceContainer.Resolve<ILogger>("logger");
|
||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
||||
_policyService = ServiceContainer.Resolve<IPolicyService>();
|
||||
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>();
|
||||
|
||||
PageTitle = AppResources.VerifyMasterPassword;
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
@@ -205,7 +209,7 @@ namespace Bit.App.Pages
|
||||
|
||||
if (BiometricLock)
|
||||
{
|
||||
BiometricIntegrityValid = await _biometricService.ValidateIntegrityAsync();
|
||||
BiometricIntegrityValid = await _platformUtilsService.IsBiometricIntegrityValidAsync();
|
||||
if (!_biometricIntegrityValid)
|
||||
{
|
||||
BiometricButtonVisible = false;
|
||||
@@ -294,6 +298,7 @@ namespace Bit.App.Pages
|
||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdfConfig);
|
||||
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
|
||||
var passwordValid = false;
|
||||
MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null;
|
||||
|
||||
if (storedKeyHash != null)
|
||||
{
|
||||
@@ -305,9 +310,11 @@ namespace Bit.App.Pages
|
||||
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
|
||||
var request = new PasswordVerificationRequest();
|
||||
request.MasterPasswordHash = keyHash;
|
||||
|
||||
try
|
||||
{
|
||||
await _apiService.PostAccountVerifyPasswordAsync(request);
|
||||
var response = await _apiService.PostAccountVerifyPasswordAsync(request);
|
||||
enforcedMasterPasswordOptions = response.MasterPasswordPolicy;
|
||||
passwordValid = true;
|
||||
var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization);
|
||||
await _cryptoService.SetKeyHashAsync(localKeyHash);
|
||||
@@ -328,6 +335,14 @@ namespace Bit.App.Pages
|
||||
var pinKey = await _cryptoService.MakePinKeyAysnc(decPin, _email, kdfConfig);
|
||||
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey));
|
||||
}
|
||||
|
||||
if (await RequirePasswordChangeAsync(enforcedMasterPasswordOptions))
|
||||
{
|
||||
// Save the ForcePasswordResetReason to force a password reset after unlock
|
||||
await _stateService.SetForcePasswordResetReasonAsync(
|
||||
ForcePasswordResetReason.WeakMasterPasswordOnLogin);
|
||||
}
|
||||
|
||||
MasterPassword = string.Empty;
|
||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
||||
await SetKeyAndContinueAsync(key);
|
||||
@@ -352,6 +367,37 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the master password requires updating to meet the enforced policy requirements
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
private async Task<bool> RequirePasswordChangeAsync(MasterPasswordPolicyOptions options = null)
|
||||
{
|
||||
// If no policy options are provided, attempt to load them from the policy service
|
||||
var enforcedOptions = options ?? await _policyService.GetMasterPasswordPolicyOptions();
|
||||
|
||||
// No policy to enforce on login/unlock
|
||||
if (!(enforcedOptions is { EnforceOnLogin: true }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var strength = _passwordGenerationService.PasswordStrength(
|
||||
MasterPassword, _passwordGenerationService.GetPasswordStrengthUserInput(_email))?.Score;
|
||||
|
||||
if (!strength.HasValue)
|
||||
{
|
||||
_logger.Error("Unable to evaluate master password strength during unlock");
|
||||
return false;
|
||||
}
|
||||
|
||||
return !await _policyService.EvaluateMasterPassword(
|
||||
strength.Value,
|
||||
MasterPassword,
|
||||
enforcedOptions
|
||||
);
|
||||
}
|
||||
|
||||
public async Task LogOutAsync()
|
||||
{
|
||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LogoutConfirmation,
|
||||
@@ -385,7 +431,8 @@ namespace Bit.App.Pages
|
||||
|
||||
public async Task PromptBiometricAsync()
|
||||
{
|
||||
BiometricIntegrityValid = await _biometricService.ValidateIntegrityAsync();
|
||||
BiometricIntegrityValid = await _platformUtilsService.IsBiometricIntegrityValidAsync();
|
||||
BiometricButtonVisible = BiometricIntegrityValid;
|
||||
if (!BiometricLock || !BiometricIntegrityValid)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -9,23 +9,23 @@
|
||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
||||
x:DataType="pages:LoginPageViewModel"
|
||||
x:Name="_page"
|
||||
Title="{Binding PageTitle}">
|
||||
Title="{Binding PageTitle}"
|
||||
AutomationId="PageTitleLabel">
|
||||
|
||||
<ContentPage.BindingContext>
|
||||
<pages:LoginPageViewModel />
|
||||
</ContentPage.BindingContext>
|
||||
|
||||
<ContentPage.ToolbarItems>
|
||||
<controls:ExtendedToolbarItem
|
||||
x:Name="_accountAvatar"
|
||||
x:Key="accountAvatar"
|
||||
IconImageSource="{Binding AvatarImageSource}"
|
||||
Command="{Binding Source={x:Reference _accountListOverlay}, Path=ToggleVisibililtyCommand}"
|
||||
Order="Primary"
|
||||
Priority="-1"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"
|
||||
AutomationId="AccountIconButton" />
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<ContentPage.Resources>
|
||||
@@ -34,7 +34,8 @@
|
||||
<ToolbarItem Icon="more_vert.png" Clicked="More_Clicked" Order="Primary"
|
||||
x:Name="_moreItem" x:Key="moreItem"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
AutomationId="OptionsButton" />
|
||||
<ToolbarItem Text="{u:I18n GetPasswordHint}"
|
||||
x:Key="getPasswordHint"
|
||||
x:Name="_getPasswordHint"
|
||||
@@ -75,7 +76,9 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding LogInCommand}" />
|
||||
ReturnCommand="{Binding LogInCommand}"
|
||||
AutomationId="MasterPasswordEntry"
|
||||
/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -84,6 +87,7 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="1"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationId="PasswordVisibilityToggle"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"/>
|
||||
<Label
|
||||
@@ -93,7 +97,9 @@
|
||||
Padding="0,5,0,0"
|
||||
Grid.Row="2"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2">
|
||||
Grid.ColumnSpan="2"
|
||||
AutomationId="GetMasterPasswordHintLabel"
|
||||
>
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="Hint_Clicked" />
|
||||
</Label.GestureRecognizers>
|
||||
@@ -104,19 +110,24 @@
|
||||
<Button x:Name="_loginWithMasterPassword"
|
||||
Text="{u:I18n LogInWithMasterPassword}"
|
||||
StyleClass="btn-primary"
|
||||
Clicked="LogIn_Clicked" />
|
||||
Clicked="LogIn_Clicked"
|
||||
AutomationId="LogInWithMasterPasswordButton"
|
||||
/>
|
||||
<controls:IconLabelButton
|
||||
HorizontalOptions="Fill"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
Icon="{Binding Source={x:Static core:BitwardenIcons.Device}}"
|
||||
Label="{u:I18n LogInWithAnotherDevice}"
|
||||
ButtonCommand="{Binding LogInWithDeviceCommand}"
|
||||
IsVisible="{Binding IsKnownDevice}"/>
|
||||
IsVisible="{Binding IsKnownDevice}"
|
||||
AutomationId="LogInWithAnotherDeviceButton"
|
||||
/>
|
||||
<controls:IconLabelButton
|
||||
HorizontalOptions="Fill"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
Icon="{Binding Source={x:Static core:BitwardenIcons.Suitcase}}"
|
||||
Label="{u:I18n LogInSso}">
|
||||
Label="{u:I18n LogInSso}"
|
||||
AutomationId="LogInWithSsoButton">
|
||||
<controls:IconLabelButton.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="LogInSSO_Clicked" />
|
||||
</controls:IconLabelButton.GestureRecognizers>
|
||||
@@ -124,12 +135,15 @@
|
||||
<Label
|
||||
Text="{Binding LoggingInAsText}"
|
||||
StyleClass="text-sm"
|
||||
Margin="0,40,0,0"/>
|
||||
Margin="0,40,0,0"
|
||||
AutomationId="LoggingInAsLabel"
|
||||
/>
|
||||
<Label
|
||||
Text="{u:I18n NotYou}"
|
||||
StyleClass="text-md"
|
||||
HorizontalOptions="Start"
|
||||
TextColor="{DynamicResource HyperlinkColor}">
|
||||
TextColor="{DynamicResource HyperlinkColor}"
|
||||
AutomationId="NotYouLabel">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="Cancel_Clicked" />
|
||||
</Label.GestureRecognizers>
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace Bit.App.Pages
|
||||
private bool _isEmailEnabled;
|
||||
private bool _isKnownDevice;
|
||||
private bool _isExecutingLogin;
|
||||
private string _environmentHostName;
|
||||
|
||||
public LoginPageViewModel()
|
||||
{
|
||||
@@ -115,6 +116,16 @@ namespace Bit.App.Pages
|
||||
set => SetProperty(ref _isKnownDevice, value);
|
||||
}
|
||||
|
||||
public string EnvironmentDomainName
|
||||
{
|
||||
get => _environmentHostName;
|
||||
set => SetProperty(ref _environmentHostName, value,
|
||||
additionalPropertyNames: new string[]
|
||||
{
|
||||
nameof(LoggingInAsText)
|
||||
});
|
||||
}
|
||||
|
||||
public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; }
|
||||
public Command LogInCommand { get; }
|
||||
public Command TogglePasswordCommand { get; }
|
||||
@@ -122,7 +133,7 @@ namespace Bit.App.Pages
|
||||
public ICommand LogInWithDeviceCommand { get; }
|
||||
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
|
||||
public string PasswordVisibilityAccessibilityText => ShowPassword ? AppResources.PasswordIsVisibleTapToHide : AppResources.PasswordIsNotVisibleTapToShow;
|
||||
public string LoggingInAsText => string.Format(AppResources.LoggingInAsX, Email);
|
||||
public string LoggingInAsText => string.Format(AppResources.LoggingInAsXOnY, Email, EnvironmentDomainName);
|
||||
public bool IsIosExtension { get; set; }
|
||||
public bool CanRemoveAccount { get; set; }
|
||||
public Action StartTwoFactorAction { get; set; }
|
||||
@@ -151,6 +162,7 @@ namespace Bit.App.Pages
|
||||
Email = await _stateService.GetRememberedEmailAsync();
|
||||
}
|
||||
CanRemoveAccount = await _stateService.GetActiveUserEmailAsync() != Email;
|
||||
EnvironmentDomainName = CoreHelpers.GetDomain((await _stateService.GetPreAuthEnvironmentUrlsAsync())?.Base);
|
||||
IsKnownDevice = await _apiService.GetKnownDeviceAsync(Email, await _appIdService.GetAppIdAsync());
|
||||
}
|
||||
catch (ApiException apiEx) when (apiEx.Error.StatusCode == System.Net.HttpStatusCode.Unauthorized)
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
<Label
|
||||
Text="{Binding LogInAttemptByLabel}"
|
||||
FontSize="Small"
|
||||
Margin="0,0,0,24"/>
|
||||
Margin="0,0,0,24"
|
||||
AutomationId="LogInAttemptByLabel" />
|
||||
<Label
|
||||
Text="{u:I18n FingerprintPhrase}"
|
||||
FontSize="Small"
|
||||
@@ -41,7 +42,8 @@
|
||||
FormattedText="{Binding LoginRequest.FingerprintPhrase}"
|
||||
FontSize="Medium"
|
||||
TextColor="{DynamicResource FingerprintPhrase}"
|
||||
Margin="0,0,0,27"/>
|
||||
Margin="0,0,0,27"
|
||||
AutomationId="FingerprintValueLabel" />
|
||||
<Label
|
||||
Text="{u:I18n DeviceType}"
|
||||
FontSize="Small"
|
||||
@@ -49,7 +51,8 @@
|
||||
<Label
|
||||
Text="{Binding LoginRequest.DeviceType}"
|
||||
FontSize="Small"
|
||||
Margin="0,0,0,21"/>
|
||||
Margin="0,0,0,21"
|
||||
AutomationId="DeviceTypeValueLabel" />
|
||||
<Label
|
||||
Text="{u:I18n IpAddress}"
|
||||
IsVisible="{Binding ShowIpAddress}"
|
||||
@@ -59,7 +62,8 @@
|
||||
Text="{Binding LoginRequest.IpAddress}"
|
||||
IsVisible="{Binding ShowIpAddress}"
|
||||
FontSize="Small"
|
||||
Margin="0,0,0,21"/>
|
||||
Margin="0,0,0,21"
|
||||
AutomationId="IpAddressValueLabel" />
|
||||
<Label
|
||||
Text="{u:I18n Time}"
|
||||
FontSize="Small"
|
||||
@@ -67,7 +71,8 @@
|
||||
<Label
|
||||
Text="{Binding TimeOfRequestText}"
|
||||
FontSize="Small"
|
||||
Margin="0,0,0,57"/>
|
||||
Margin="0,0,0,57"
|
||||
AutomationId="TimeOfRequestValueLabel" />
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
||||
@@ -75,11 +80,13 @@
|
||||
Text="{u:I18n ConfirmLogIn}"
|
||||
Command="{Binding AcceptRequestCommand}"
|
||||
Margin="0,0,0,17"
|
||||
StyleClass="btn-primary"/>
|
||||
StyleClass="btn-primary"
|
||||
AutomationId="ConfirmLoginButton" />
|
||||
<Button
|
||||
Text="{u:I18n DenyLogIn}"
|
||||
Command="{Binding RejectRequestCommand}"
|
||||
StyleClass="btn-secundary"/>
|
||||
StyleClass="btn-secundary"
|
||||
AutomationId="DenyLoginButton" />
|
||||
|
||||
</StackLayout>
|
||||
</pages:BaseContentPage>
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
Text="{u:I18n LogInInitiated}"
|
||||
FontSize="Title"
|
||||
FontAttributes="Bold"
|
||||
Margin="0,14,0,21"/>
|
||||
Margin="0,14,0,21"
|
||||
AutomationId="LogInInitiatedLabel" />
|
||||
<Label
|
||||
Text="{u:I18n ANotificationHasBeenSentToYourDevice}"
|
||||
FontSize="Small"
|
||||
@@ -40,13 +41,15 @@
|
||||
<controls:MonoLabel
|
||||
FormattedText="{Binding FingerprintPhrase}"
|
||||
FontSize="Medium"
|
||||
TextColor="{DynamicResource FingerprintPhrase}"/>
|
||||
TextColor="{DynamicResource FingerprintPhrase}"
|
||||
AutomationId="FingerprintPhraseValue" />
|
||||
<Label
|
||||
Text="{u:I18n ResendNotification}"
|
||||
StyleClass="text-md"
|
||||
HorizontalOptions="Start"
|
||||
Margin="0,40,0,0"
|
||||
TextColor="{DynamicResource HyperlinkColor}">
|
||||
TextColor="{DynamicResource HyperlinkColor}"
|
||||
AutomationId="ResendNotificationButton">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding CreatePasswordlessLoginCommand}" />
|
||||
</Label.GestureRecognizers>
|
||||
@@ -64,7 +67,8 @@
|
||||
VerticalTextAlignment="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
Margin="5, 0"
|
||||
TextColor="{DynamicResource HyperlinkColor}">
|
||||
TextColor="{DynamicResource HyperlinkColor}"
|
||||
AutomationId="ViewAllLoginOptionsButton">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Command="{Binding CloseCommand}" />
|
||||
</Label.GestureRecognizers>
|
||||
|
||||
@@ -121,9 +121,8 @@ namespace Bit.App.Pages
|
||||
|
||||
var ssoToken = response.Token;
|
||||
|
||||
|
||||
var passwordOptions = new PasswordGenerationOptions(true);
|
||||
passwordOptions.Length = 64;
|
||||
var passwordOptions = PasswordGenerationOptions.CreateDefault
|
||||
.WithLength(64);
|
||||
|
||||
var codeVerifier = await _passwordGenerationService.GeneratePasswordAsync(passwordOptions);
|
||||
var codeVerifierHash = await _cryptoFunctionService.HashAsync(codeVerifier, CryptoHashAlgorithm.Sha256);
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
x:Name="_email"
|
||||
Text="{Binding Email}"
|
||||
Keyboard="Email"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="EmailAddressEntry"/>
|
||||
</StackLayout>
|
||||
<Grid StyleClass="box-row">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -59,7 +60,8 @@
|
||||
IsTextPredictionEnabled="False"
|
||||
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="MasterPasswordEntry"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -69,7 +71,8 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"/>
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
|
||||
AutomationId="PasswordVisibilityToggle"/>
|
||||
</Grid>
|
||||
<Label
|
||||
StyleClass="box-sub-label"
|
||||
@@ -109,7 +112,8 @@
|
||||
IsTextPredictionEnabled="False"
|
||||
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ConfirmMasterPasswordEntry"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -118,6 +122,7 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationId="ConfirmPasswordVisibilityToggle"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}" />
|
||||
</Grid>
|
||||
@@ -130,7 +135,8 @@
|
||||
Text="{Binding Hint}"
|
||||
StyleClass="box-value"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="MasterPasswordHintLabel" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n MasterPasswordHintDescription}"
|
||||
@@ -142,7 +148,8 @@
|
||||
IsToggled="{Binding CheckExposedMasterPassword}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="Start"
|
||||
Margin="0, 0, 10, 0"/>
|
||||
Margin="0, 0, 10, 0"
|
||||
AutomationId="CheckExposedMasterPasswordToggle"/>
|
||||
<Label
|
||||
Text="{u:I18n CheckKnownDataBreachesForThisPassword}"
|
||||
StyleClass="box-footer-label"
|
||||
@@ -154,7 +161,8 @@
|
||||
IsToggled="{Binding AcceptPolicies}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="Start"
|
||||
Margin="0, 0, 10, 0"/>
|
||||
Margin="0, 0, 10, 0"
|
||||
AutomationId="AcceptPoliciesToggle"/>
|
||||
<Label StyleClass="box-footer-label"
|
||||
HorizontalOptions="Fill">
|
||||
<Label.FormattedText>
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
BackgroundColor="Transparent"
|
||||
BorderColor="{DynamicResource PrimaryColor}">
|
||||
<Label
|
||||
Text="{u:I18n UpdateMasterPasswordWarning}"
|
||||
Text="{Binding UpdateMasterPasswordWarningText }"
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
HorizontalTextAlignment="Center" />
|
||||
</Frame>
|
||||
@@ -74,6 +74,40 @@
|
||||
HorizontalTextAlignment="Start" />
|
||||
</Frame>
|
||||
</Grid>
|
||||
<Grid StyleClass="box-row" IsVisible="{Binding RequireCurrentPassword }">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label
|
||||
Text="{u:I18n CurrentMasterPassword}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
<controls:MonoEntry
|
||||
x:Name="_currentMasterPassword"
|
||||
Text="{Binding CurrentMasterPassword}"
|
||||
StyleClass="box-value"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False"
|
||||
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
Command="{Binding TogglePasswordCommand}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}" />
|
||||
</Grid>
|
||||
<Grid StyleClass="box-row">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
|
||||
@@ -1,27 +1,68 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Models.Request;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.CommunityToolkit.ObjectModel;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public class UpdateTempPasswordPageViewModel : BaseChangePasswordViewModel
|
||||
{
|
||||
private readonly IUserVerificationService _userVerificationService;
|
||||
|
||||
private ForcePasswordResetReason _reason = ForcePasswordResetReason.AdminForcePasswordReset;
|
||||
|
||||
public UpdateTempPasswordPageViewModel()
|
||||
{
|
||||
PageTitle = AppResources.UpdateMasterPassword;
|
||||
TogglePasswordCommand = new Command(TogglePassword);
|
||||
ToggleConfirmPasswordCommand = new Command(ToggleConfirmPassword);
|
||||
SubmitCommand = new Command(async () => await SubmitAsync());
|
||||
SubmitCommand = new AsyncCommand(SubmitAsync,
|
||||
onException: ex => HandleException(ex),
|
||||
allowsMultipleExecutions: false);
|
||||
|
||||
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>();
|
||||
}
|
||||
|
||||
public Command SubmitCommand { get; }
|
||||
public AsyncCommand SubmitCommand { get; }
|
||||
public Command TogglePasswordCommand { get; }
|
||||
public Command ToggleConfirmPasswordCommand { get; }
|
||||
public Action UpdateTempPasswordSuccessAction { get; set; }
|
||||
public Action LogOutAction { get; set; }
|
||||
public string CurrentMasterPassword { get; set; }
|
||||
|
||||
public override async Task InitAsync(bool forceSync = false)
|
||||
{
|
||||
await base.InitAsync(forceSync);
|
||||
|
||||
var forcePasswordResetReason = await _stateService.GetForcePasswordResetReasonAsync();
|
||||
|
||||
if (forcePasswordResetReason.HasValue)
|
||||
{
|
||||
_reason = forcePasswordResetReason.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool RequireCurrentPassword
|
||||
{
|
||||
get => _reason == ForcePasswordResetReason.WeakMasterPasswordOnLogin;
|
||||
}
|
||||
|
||||
public string UpdateMasterPasswordWarningText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _reason == ForcePasswordResetReason.WeakMasterPasswordOnLogin
|
||||
? AppResources.UpdateWeakMasterPasswordWarning
|
||||
: AppResources.UpdateMasterPasswordWarning;
|
||||
}
|
||||
}
|
||||
|
||||
public void TogglePassword()
|
||||
{
|
||||
@@ -42,6 +83,12 @@ namespace Bit.App.Pages
|
||||
return;
|
||||
}
|
||||
|
||||
if (RequireCurrentPassword &&
|
||||
!await _userVerificationService.VerifyUser(CurrentMasterPassword, VerificationType.MasterPassword))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve details for key generation
|
||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
||||
var email = await _stateService.GetEmailAsync();
|
||||
@@ -53,21 +100,29 @@ namespace Bit.App.Pages
|
||||
// Create new encKey for the User
|
||||
var newEncKey = await _cryptoService.RemakeEncKeyAsync(key);
|
||||
|
||||
// Create request
|
||||
var request = new UpdateTempPasswordRequest
|
||||
{
|
||||
Key = newEncKey.Item2.EncryptedString,
|
||||
NewMasterPasswordHash = masterPasswordHash,
|
||||
MasterPasswordHint = Hint
|
||||
};
|
||||
|
||||
// Initiate API action
|
||||
try
|
||||
{
|
||||
await _deviceActionService.ShowLoadingAsync(AppResources.UpdatingPassword);
|
||||
await _apiService.PutUpdateTempPasswordAsync(request);
|
||||
|
||||
switch (_reason)
|
||||
{
|
||||
case ForcePasswordResetReason.AdminForcePasswordReset:
|
||||
await UpdateTempPasswordAsync(masterPasswordHash, newEncKey.Item2.EncryptedString);
|
||||
break;
|
||||
case ForcePasswordResetReason.WeakMasterPasswordOnLogin:
|
||||
await UpdatePasswordAsync(masterPasswordHash, newEncKey.Item2.EncryptedString);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
await _deviceActionService.HideLoadingAsync();
|
||||
|
||||
// Clear the force reset password reason
|
||||
await _stateService.SetForcePasswordResetReasonAsync(null);
|
||||
|
||||
_platformUtilsService.ShowToast(null, null, AppResources.UpdatedMasterPassword);
|
||||
|
||||
UpdateTempPasswordSuccessAction?.Invoke();
|
||||
}
|
||||
catch (ApiException e)
|
||||
@@ -85,5 +140,32 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateTempPasswordAsync(string newMasterPasswordHash, string newEncKey)
|
||||
{
|
||||
var request = new UpdateTempPasswordRequest
|
||||
{
|
||||
Key = newEncKey,
|
||||
NewMasterPasswordHash = newMasterPasswordHash,
|
||||
MasterPasswordHint = Hint
|
||||
};
|
||||
|
||||
await _apiService.PutUpdateTempPasswordAsync(request);
|
||||
}
|
||||
|
||||
private async Task UpdatePasswordAsync(string newMasterPasswordHash, string newEncKey)
|
||||
{
|
||||
var currentPasswordHash = await _cryptoService.HashPasswordAsync(CurrentMasterPassword, null);
|
||||
|
||||
var request = new PasswordRequest
|
||||
{
|
||||
MasterPasswordHash = currentPasswordHash,
|
||||
Key = newEncKey,
|
||||
NewMasterPasswordHash = newMasterPasswordHash,
|
||||
MasterPasswordHint = Hint
|
||||
};
|
||||
|
||||
await _apiService.PostPasswordAsync(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
Clicked="Clear_Clicked"
|
||||
Order="Secondary"
|
||||
x:Name="_clearItem"
|
||||
x:Key="clearItem" />
|
||||
x:Key="clearItem"
|
||||
AutomationId="ClearPasswordList" />
|
||||
<ToolbarItem Icon="more_vert.png"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
@@ -43,7 +44,8 @@
|
||||
Margin="20, 0"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NoPasswordsDisplayedLabel"></Label>
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
|
||||
ItemsSource="{Binding History}"
|
||||
@@ -56,7 +58,8 @@
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10"
|
||||
RowSpacing="0"
|
||||
ColumnSpacing="10">
|
||||
ColumnSpacing="10"
|
||||
AutomationId="GeneratedPasswordRow">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -71,12 +74,14 @@
|
||||
Grid.Column="0"
|
||||
Grid.Row="0"
|
||||
StyleClass="list-title, list-title-platform, text-html"
|
||||
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
|
||||
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}"
|
||||
AutomationId="GeneratedPasswordValue" />
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
StyleClass="list-subtitle, list-subtitle-platform"
|
||||
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
|
||||
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}"
|
||||
AutomationId="GeneratedPasswordDateLabel" />
|
||||
<controls:IconButton
|
||||
StyleClass="list-row-button, list-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Paste}}"
|
||||
@@ -86,7 +91,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}" />
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}"
|
||||
AutomationId="CopyPasswordValueButton" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
|
||||
@@ -71,7 +71,8 @@
|
||||
<Label
|
||||
Text="{u:I18n PasswordGeneratorPolicyInEffect}"
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="PasswordGeneratorPolicyInEffectLabel" />
|
||||
</Frame>
|
||||
</Grid>
|
||||
<Grid IsVisible="{Binding IsUsername, Converter={StaticResource inverseBool}}"
|
||||
@@ -82,21 +83,24 @@
|
||||
x:Name="lblPassword"
|
||||
StyleClass="text-lg, text-html"
|
||||
Text="{Binding ColoredPassword, Mode=OneWay}"
|
||||
Margin="0, 20" />
|
||||
Margin="0, 20"
|
||||
AutomationId="GeneratedPasswordLabel" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
Command="{Binding CopyCommand}"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}" />
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}"
|
||||
AutomationId="CopyValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Generate}}"
|
||||
Command="{Binding RegenerateCommand}"
|
||||
Grid.Column="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n GeneratePassword}" />
|
||||
AutomationProperties.Name="{u:I18n GeneratePassword}"
|
||||
AutomationId="RegenerateValueButton" />
|
||||
</Grid>
|
||||
<Grid IsVisible="{Binding IsUsername}"
|
||||
StyleClass="box-row"
|
||||
@@ -107,21 +111,24 @@
|
||||
StyleClass="text-lg, text-html"
|
||||
Text="{Binding ColoredUsername, Mode=OneWay}"
|
||||
Margin="0, 20"
|
||||
HorizontalOptions="Start" />
|
||||
HorizontalOptions="Start"
|
||||
AutomationId="GeneratedPasswordLabel" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
Command="{Binding CopyCommand}"
|
||||
Grid.Column="1"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyUsername}" />
|
||||
AutomationProperties.Name="{u:I18n CopyUsername}"
|
||||
AutomationId="CopyValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Generate}}"
|
||||
Command="{Binding RegenerateUsernameCommand}"
|
||||
Grid.Column="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n GenerateUsername}" />
|
||||
AutomationProperties.Name="{u:I18n GenerateUsername}"
|
||||
AutomationId="RegenerateValueButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator"/>
|
||||
<StackLayout StyleClass="box"
|
||||
@@ -135,7 +142,8 @@
|
||||
ItemsSource="{Binding GeneratorTypeOptions, Mode=OneTime}"
|
||||
SelectedItem="{Binding GeneratorTypeSelected}"
|
||||
ItemDisplayBinding="{Binding ., Converter={StaticResource localizableEnum}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="GeneratorTypePicker" />
|
||||
</StackLayout>
|
||||
<Label Text="{u:I18n Options, Header=True}"
|
||||
StyleClass="box-header, box-header-platform"
|
||||
@@ -161,7 +169,8 @@
|
||||
ItemsSource="{Binding UsernameTypeOptions, Mode=OneTime}"
|
||||
SelectedItem="{Binding UsernameTypeSelected}"
|
||||
ItemDisplayBinding="{Binding ., Converter={StaticResource localizableEnum}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="UsernameTypePicker" />
|
||||
<Label
|
||||
StyleClass="box-footer-label"
|
||||
Text="{Binding UsernameTypeDescriptionLabel}" />
|
||||
@@ -172,7 +181,8 @@
|
||||
StyleClass="box-label" />
|
||||
<Entry x:Name="_plusAddressedEmailEntry"
|
||||
Text="{Binding PlusAddressedEmail}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="PlusAddressedEmailEntry" />
|
||||
<Label IsVisible="{Binding ShowUsernameEmailType}"
|
||||
Text="{u:I18n EmailType}"
|
||||
StyleClass="box-label"
|
||||
@@ -203,7 +213,8 @@
|
||||
<Entry
|
||||
x:Name="_catchAllEmailDomainNameEntry"
|
||||
Text="{Binding CatchAllEmailDomain}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="CatchAllEmailDomainEntry" />
|
||||
<Label IsVisible="{Binding ShowUsernameEmailType}"
|
||||
Text="{u:I18n EmailType}"
|
||||
StyleClass="box-label"
|
||||
@@ -236,26 +247,27 @@
|
||||
ItemsSource="{Binding ForwardedEmailServiceTypeOptions, Mode=OneTime}"
|
||||
SelectedItem="{Binding ForwardedEmailServiceSelected}"
|
||||
ItemDisplayBinding="{Binding ., Converter={StaticResource localizableEnum}}"
|
||||
StyleClass="box-value" />
|
||||
<!--ANONADDY OPTIONS-->
|
||||
<Grid IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.AnonAddy}}"
|
||||
Grid.RowDefinitions="Auto,*"
|
||||
Grid.ColumnDefinitions="*,Auto">
|
||||
StyleClass="box-value"
|
||||
AutomationId="ServiceTypePicker" />
|
||||
<Grid
|
||||
Grid.RowDefinitions="Auto,*"
|
||||
Grid.ColumnDefinitions="*,Auto">
|
||||
<Label
|
||||
Margin="0,10,0,0"
|
||||
Text="{u:I18n APIAccessToken}"
|
||||
Text="{Binding ForwardedEmailApiSecretLabel}"
|
||||
StyleClass="box-label"/>
|
||||
<Entry
|
||||
x:Name="_anonAddyApiAccessTokenEntry"
|
||||
Text="{Binding AnonAddyApiAccessToken}"
|
||||
IsPassword="{Binding ShowAnonAddyApiAccessToken, Converter={StaticResource inverseBool}}"
|
||||
Grid.Row="1"/>
|
||||
Text="{Binding ForwardedEmailApiSecret}"
|
||||
IsPassword="{Binding ShowForwardedEmailApiSecret, Converter={StaticResource inverseBool}}"
|
||||
Grid.Row="1"
|
||||
AutomationId="ForwardedEmailApiSecretEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowAnonAddyApiAccessToken, Converter={StaticResource inverseBool, iconGlyphConverter}, ConverterParameter={x:Static u:BooleanGlyphType.Eye}}"
|
||||
Text="{Binding ShowForwardedEmailApiSecret, Converter={StaticResource inverseBool, iconGlyphConverter}, ConverterParameter={x:Static u:BooleanGlyphType.Eye}}"
|
||||
Command="{Binding ToggleForwardedEmailHiddenValueCommand}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"/>
|
||||
Grid.Column="1"
|
||||
AutomationId="ShowForwardedEmailApiSecretButton" />
|
||||
</Grid>
|
||||
<Label IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.AnonAddy}}"
|
||||
Text="{u:I18n DomainNameRequiredParenthesis}"
|
||||
@@ -264,91 +276,8 @@
|
||||
<Entry IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.AnonAddy}}"
|
||||
x:Name="_anonAddyDomainNameEntry"
|
||||
Text="{Binding AnonAddyDomainName}"
|
||||
StyleClass="box-value"/>
|
||||
<!--FIREFOX RELAY OPTIONS-->
|
||||
<Grid StyleClass="box-row, box-row-input"
|
||||
IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.FirefoxRelay}}"
|
||||
Grid.RowDefinitions="Auto,*"
|
||||
Grid.ColumnDefinitions="*,Auto">
|
||||
<Label
|
||||
Text="{u:I18n APIAccessToken}"
|
||||
StyleClass="box-label"/>
|
||||
<Entry
|
||||
x:Name="_firefoxRelayApiAccessTokenEntry"
|
||||
Text="{Binding FirefoxRelayApiAccessToken}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
IsPassword="{Binding ShowFirefoxRelayApiAccessToken, Converter={StaticResource inverseBool}}"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowFirefoxRelayApiAccessToken, Converter={StaticResource inverseBool, iconGlyphConverter}, ConverterParameter={x:Static u:BooleanGlyphType.Eye}}"
|
||||
Command="{Binding ToggleForwardedEmailHiddenValueCommand}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
<!--SIMPLELOGIN OPTIONS-->
|
||||
<Grid StyleClass="box-row, box-row-input"
|
||||
IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.SimpleLogin}}"
|
||||
Grid.RowDefinitions="Auto,*"
|
||||
Grid.ColumnDefinitions="*,Auto">
|
||||
<Label
|
||||
Text="{u:I18n APIKeyRequiredParenthesis}"
|
||||
StyleClass="box-label"/>
|
||||
<Entry
|
||||
x:Name="_simpleLoginApiKeyEntry"
|
||||
Text="{Binding SimpleLoginApiKey}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
IsPassword="{Binding ShowSimpleLoginApiKey, Converter={StaticResource inverseBool}}"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowSimpleLoginApiKey, Converter={StaticResource inverseBool, iconGlyphConverter}, ConverterParameter={x:Static u:BooleanGlyphType.Eye}}"
|
||||
Command="{Binding ToggleForwardedEmailHiddenValueCommand}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
<!--DUCKDUCKGO OPTIONS-->
|
||||
<Grid StyleClass="box-row, box-row-input"
|
||||
IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.DuckDuckGo}}"
|
||||
Grid.RowDefinitions="Auto,*"
|
||||
Grid.ColumnDefinitions="*,Auto">
|
||||
<Label
|
||||
Text="{u:I18n APIKeyRequiredParenthesis}"
|
||||
StyleClass="box-label"/>
|
||||
<Entry
|
||||
x:Name="_duckDuckGoApiAccessTokenEntry"
|
||||
Text="{Binding DuckDuckGoApiKey}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
IsPassword="{Binding ShowDuckDuckGoApiKey, Converter={StaticResource inverseBool}}"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowDuckDuckGoApiKey, Converter={StaticResource inverseBool, iconGlyphConverter}, ConverterParameter={x:Static u:BooleanGlyphType.Eye}}"
|
||||
Command="{Binding ToggleForwardedEmailHiddenValueCommand}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
<!--FASTMAIL OPTIONS-->
|
||||
<Grid StyleClass="box-row, box-row-input"
|
||||
IsVisible="{Binding ForwardedEmailServiceSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:ForwardedEmailServiceType.Fastmail}}"
|
||||
Grid.RowDefinitions="Auto,*"
|
||||
Grid.ColumnDefinitions="*,Auto">
|
||||
<Label
|
||||
Text="{u:I18n APIKeyRequiredParenthesis}"
|
||||
StyleClass="box-label"/>
|
||||
<Entry
|
||||
x:Name="_fastmailApiAccessTokenEntry"
|
||||
Text="{Binding FastmailApiKey}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
IsPassword="{Binding ShowFastmailApiKey, Converter={StaticResource inverseBool}}"/>
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowFastmailApiKey, Converter={StaticResource iconGlyphConverter}, ConverterParameter={x:Static u:BooleanGlyphType.Eye}}"
|
||||
Command="{Binding ToggleForwardedEmailHiddenValueCommand}"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"/>
|
||||
</Grid>
|
||||
StyleClass="box-value"
|
||||
AutomationId="AnonAddyDomainNameEntry" />
|
||||
</StackLayout>
|
||||
<!--RANDOM WORD OPTIONS-->
|
||||
<Grid IsVisible="{Binding UsernameTypeSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:UsernameType.RandomWord}}">
|
||||
@@ -359,7 +288,8 @@
|
||||
<Switch
|
||||
IsToggled="{Binding CapitalizeRandomWordUsername}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="CapitalizeRandomWordUsernameToggle" />
|
||||
</Grid>
|
||||
<BoxView IsVisible="{Binding UsernameTypeSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:UsernameType.RandomWord}}"
|
||||
StyleClass="box-row-separator" />
|
||||
@@ -371,7 +301,8 @@
|
||||
<Switch
|
||||
IsToggled="{Binding IncludeNumberRandomWordUsername}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="IncludeNumberRandomWordUsernameToggle" />
|
||||
</Grid>
|
||||
<BoxView IsVisible="{Binding UsernameTypeSelected, Converter={StaticResource enumToBool}, ConverterParameter={x:Static enums:UsernameType.RandomWord}}"
|
||||
StyleClass="box-row-separator" />
|
||||
@@ -386,7 +317,8 @@
|
||||
x:Name="_passwordTypePicker"
|
||||
ItemsSource="{Binding PasswordTypeOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding PasswordTypeSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="PasswordTypePicker" />
|
||||
</StackLayout>
|
||||
<StackLayout Spacing="0"
|
||||
Padding="0"
|
||||
@@ -403,12 +335,14 @@
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="NumberOfWordsLabel" />
|
||||
<controls:ExtendedStepper
|
||||
Value="{Binding NumWords}"
|
||||
Maximum="20"
|
||||
Minimum="3"
|
||||
Increment="1" />
|
||||
Increment="1"
|
||||
AutomationId="NumberOfWordsStepper" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
@@ -419,7 +353,8 @@
|
||||
Text="{Binding WordSeparator}"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False"
|
||||
StyleClass="box-value">
|
||||
StyleClass="box-value"
|
||||
AutomationId="WordSeparatorEntry">
|
||||
<Entry.Effects>
|
||||
<effects:NoEmojiKeyboardEffect />
|
||||
</Entry.Effects>
|
||||
@@ -435,7 +370,8 @@
|
||||
IsEnabled="{Binding EnforcedPolicyOptions.Capitalize,
|
||||
Converter={StaticResource inverseBool}}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="CapitalizePassphraseToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
@@ -448,7 +384,8 @@
|
||||
IsEnabled="{Binding EnforcedPolicyOptions.IncludeNumber,
|
||||
Converter={StaticResource inverseBool}}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="IncludeNumbersToggle" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
<StackLayout Spacing="0" Padding="0" IsVisible="{Binding IsPassword}">
|
||||
@@ -462,7 +399,8 @@
|
||||
StyleClass="box-sub-label"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
WidthRequest="50" />
|
||||
WidthRequest="50"
|
||||
AutomationId="PasswordLengthLabel" />
|
||||
<controls:ExtendedSlider
|
||||
DragCompleted="LengthSlider_DragCompleted"
|
||||
Value="{Binding Length}"
|
||||
@@ -471,7 +409,8 @@
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Maximum="128"
|
||||
Minimum="5" />
|
||||
Minimum="5"
|
||||
AutomationId="PasswordLengthSlider" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
@@ -488,7 +427,8 @@
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n UppercaseAtoZ}"/>
|
||||
AutomationProperties.Name="{u:I18n UppercaseAtoZ}"
|
||||
AutomationId="UppercaseAtoZToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
@@ -505,7 +445,8 @@
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n LowercaseAtoZ}"/>
|
||||
AutomationProperties.Name="{u:I18n LowercaseAtoZ}"
|
||||
AutomationId="LowercaseAtoZToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
@@ -522,7 +463,8 @@
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n NumbersZeroToNine}"/>
|
||||
AutomationProperties.Name="{u:I18n NumbersZeroToNine}"
|
||||
AutomationId="NumbersZeroToNineToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
@@ -539,7 +481,8 @@
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n SpecialCharacters}"/>
|
||||
AutomationProperties.Name="{u:I18n SpecialCharacters}"
|
||||
AutomationId="SpecialCharactersToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-stepper">
|
||||
@@ -554,12 +497,14 @@
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="MinNumberValueLabel" />
|
||||
<controls:ExtendedStepper
|
||||
Value="{Binding MinNumber}"
|
||||
Maximum="5"
|
||||
Minimum="0"
|
||||
Increment="1" />
|
||||
Increment="1"
|
||||
AutomationId="MinNumberStepper" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-stepper">
|
||||
@@ -574,12 +519,14 @@
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="MinSpecialValueLabel" />
|
||||
<controls:ExtendedStepper
|
||||
Value="{Binding MinSpecial}"
|
||||
Maximum="5"
|
||||
Minimum="0"
|
||||
Increment="1" />
|
||||
Increment="1"
|
||||
AutomationId="MinSpecialStepper" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
@@ -590,7 +537,8 @@
|
||||
<Switch
|
||||
IsToggled="{Binding AvoidAmbiguousChars}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="AvoidAmbiguousCharsToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
|
||||
@@ -8,6 +8,7 @@ using Bit.App.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.CommunityToolkit.ObjectModel;
|
||||
@@ -23,7 +24,7 @@ namespace Bit.App.Pages
|
||||
private readonly IUsernameGenerationService _usernameGenerationService;
|
||||
private readonly ITokenService _tokenService;
|
||||
private readonly IDeviceActionService _deviceActionService;
|
||||
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
||||
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
||||
|
||||
private PasswordGenerationOptions _options;
|
||||
private UsernameGenerationOptions _usernameOptions;
|
||||
@@ -49,11 +50,7 @@ namespace Bit.App.Pages
|
||||
private bool _doneIniting;
|
||||
private bool _showTypePicker;
|
||||
private string _emailWebsite;
|
||||
private bool _showFirefoxRelayApiAccessToken;
|
||||
private bool _showAnonAddyApiAccessToken;
|
||||
private bool _showSimpleLoginApiKey;
|
||||
private bool _showDuckDuckGoApiKey;
|
||||
private bool _showFastmailApiKey;
|
||||
private bool _showForwardedEmailApiSecret;
|
||||
private bool _editMode;
|
||||
|
||||
public GeneratorPageViewModel()
|
||||
@@ -96,7 +93,7 @@ namespace Bit.App.Pages
|
||||
UsernameTypePromptHelpCommand = new Command(UsernameTypePromptHelp);
|
||||
RegenerateCommand = new AsyncCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
RegenerateUsernameCommand = new AsyncCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
|
||||
ToggleForwardedEmailHiddenValueCommand = new AsyncCommand(ToggleForwardedEmailHiddenValueAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||
ToggleForwardedEmailHiddenValueCommand = new Command(() => ShowForwardedEmailApiSecret = !ShowForwardedEmailApiSecret);
|
||||
CopyCommand = new AsyncCommand(CopyAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||
CloseCommand = new AsyncCommand(CloseAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
|
||||
}
|
||||
@@ -415,7 +412,6 @@ namespace Bit.App.Pages
|
||||
|
||||
public string UsernameTypeDescriptionLabel => GetUsernameTypeLabelDescription(UsernameTypeSelected);
|
||||
|
||||
|
||||
public ForwardedEmailServiceType ForwardedEmailServiceSelected
|
||||
{
|
||||
get => _usernameOptions.ServiceType;
|
||||
@@ -425,7 +421,11 @@ namespace Bit.App.Pages
|
||||
{
|
||||
_usernameOptions.ServiceType = value;
|
||||
Username = Constants.DefaultUsernameGenerated;
|
||||
TriggerPropertyChanged(nameof(ForwardedEmailServiceSelected));
|
||||
TriggerPropertyChanged(nameof(ForwardedEmailServiceSelected), new string[]
|
||||
{
|
||||
nameof(ForwardedEmailApiSecret),
|
||||
nameof(ForwardedEmailApiSecretLabel)
|
||||
});
|
||||
SaveUsernameOptionsAsync(false).FireAndForget();
|
||||
}
|
||||
}
|
||||
@@ -445,27 +445,104 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
public string AnonAddyApiAccessToken
|
||||
public string ForwardedEmailApiSecret
|
||||
{
|
||||
get => _usernameOptions.AnonAddyApiAccessToken;
|
||||
get
|
||||
{
|
||||
switch (ForwardedEmailServiceSelected)
|
||||
{
|
||||
case ForwardedEmailServiceType.AnonAddy:
|
||||
return _usernameOptions.AnonAddyApiAccessToken;
|
||||
case ForwardedEmailServiceType.DuckDuckGo:
|
||||
return _usernameOptions.DuckDuckGoApiKey;
|
||||
case ForwardedEmailServiceType.Fastmail:
|
||||
return _usernameOptions.FastMailApiKey;
|
||||
case ForwardedEmailServiceType.FirefoxRelay:
|
||||
return _usernameOptions.FirefoxRelayApiAccessToken;
|
||||
case ForwardedEmailServiceType.SimpleLogin:
|
||||
return _usernameOptions.SimpleLoginApiKey;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_usernameOptions.AnonAddyApiAccessToken != value)
|
||||
bool changed = false;
|
||||
switch (ForwardedEmailServiceSelected)
|
||||
{
|
||||
_usernameOptions.AnonAddyApiAccessToken = value;
|
||||
TriggerPropertyChanged(nameof(AnonAddyApiAccessToken));
|
||||
case ForwardedEmailServiceType.AnonAddy:
|
||||
if (_usernameOptions.AnonAddyApiAccessToken != value)
|
||||
{
|
||||
_usernameOptions.AnonAddyApiAccessToken = value;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
case ForwardedEmailServiceType.DuckDuckGo:
|
||||
if (_usernameOptions.DuckDuckGoApiKey != value)
|
||||
{
|
||||
_usernameOptions.DuckDuckGoApiKey = value;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
case ForwardedEmailServiceType.Fastmail:
|
||||
if (_usernameOptions.FastMailApiKey != value)
|
||||
{
|
||||
_usernameOptions.FastMailApiKey = value;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
case ForwardedEmailServiceType.FirefoxRelay:
|
||||
if (_usernameOptions.FirefoxRelayApiAccessToken != value)
|
||||
{
|
||||
_usernameOptions.FirefoxRelayApiAccessToken = value;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
case ForwardedEmailServiceType.SimpleLogin:
|
||||
if (_usernameOptions.SimpleLoginApiKey != value)
|
||||
{
|
||||
_usernameOptions.SimpleLoginApiKey = value;
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
TriggerPropertyChanged(nameof(ForwardedEmailApiSecret));
|
||||
SaveUsernameOptionsAsync(false).FireAndForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowAnonAddyApiAccessToken
|
||||
public string ForwardedEmailApiSecretLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showAnonAddyApiAccessToken;
|
||||
switch (ForwardedEmailServiceSelected)
|
||||
{
|
||||
case ForwardedEmailServiceType.AnonAddy:
|
||||
case ForwardedEmailServiceType.FirefoxRelay:
|
||||
return AppResources.APIAccessToken;
|
||||
case ForwardedEmailServiceType.DuckDuckGo:
|
||||
case ForwardedEmailServiceType.Fastmail:
|
||||
case ForwardedEmailServiceType.SimpleLogin:
|
||||
return AppResources.APIKeyRequiredParenthesis;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set => SetProperty(ref _showAnonAddyApiAccessToken, value);
|
||||
}
|
||||
|
||||
public bool ShowForwardedEmailApiSecret
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showForwardedEmailApiSecret;
|
||||
}
|
||||
set => SetProperty(ref _showForwardedEmailApiSecret, value);
|
||||
}
|
||||
|
||||
public string AnonAddyDomainName
|
||||
@@ -482,99 +559,6 @@ namespace Bit.App.Pages
|
||||
}
|
||||
}
|
||||
|
||||
public string FirefoxRelayApiAccessToken
|
||||
{
|
||||
get => _usernameOptions.FirefoxRelayApiAccessToken;
|
||||
set
|
||||
{
|
||||
if (_usernameOptions.FirefoxRelayApiAccessToken != value)
|
||||
{
|
||||
_usernameOptions.FirefoxRelayApiAccessToken = value;
|
||||
TriggerPropertyChanged(nameof(FirefoxRelayApiAccessToken));
|
||||
SaveUsernameOptionsAsync(false).FireAndForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowFirefoxRelayApiAccessToken
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showFirefoxRelayApiAccessToken;
|
||||
}
|
||||
set => SetProperty(ref _showFirefoxRelayApiAccessToken, value);
|
||||
}
|
||||
|
||||
public string SimpleLoginApiKey
|
||||
{
|
||||
get => _usernameOptions.SimpleLoginApiKey;
|
||||
set
|
||||
{
|
||||
if (_usernameOptions.SimpleLoginApiKey != value)
|
||||
{
|
||||
_usernameOptions.SimpleLoginApiKey = value;
|
||||
TriggerPropertyChanged(nameof(SimpleLoginApiKey));
|
||||
SaveUsernameOptionsAsync(false).FireAndForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowSimpleLoginApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showSimpleLoginApiKey;
|
||||
}
|
||||
set => SetProperty(ref _showSimpleLoginApiKey, value);
|
||||
}
|
||||
|
||||
public string DuckDuckGoApiKey
|
||||
{
|
||||
get => _usernameOptions.DuckDuckGoApiKey;
|
||||
set
|
||||
{
|
||||
if (_usernameOptions.DuckDuckGoApiKey != value)
|
||||
{
|
||||
_usernameOptions.DuckDuckGoApiKey = value;
|
||||
TriggerPropertyChanged(nameof(DuckDuckGoApiKey));
|
||||
SaveUsernameOptionsAsync(false).FireAndForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowDuckDuckGoApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showDuckDuckGoApiKey;
|
||||
}
|
||||
set => SetProperty(ref _showDuckDuckGoApiKey, value);
|
||||
}
|
||||
|
||||
|
||||
public string FastmailApiKey
|
||||
{
|
||||
get => _usernameOptions.FastMailApiKey;
|
||||
set
|
||||
{
|
||||
if (_usernameOptions.FastMailApiKey != value)
|
||||
{
|
||||
_usernameOptions.FastMailApiKey = value;
|
||||
TriggerPropertyChanged(nameof(FastmailApiKey));
|
||||
SaveUsernameOptionsAsync(false).FireAndForget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowFastmailApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showFastmailApiKey;
|
||||
}
|
||||
set => SetProperty(ref _showFastmailApiKey, value);
|
||||
}
|
||||
|
||||
public bool CapitalizeRandomWordUsername
|
||||
{
|
||||
get => _usernameOptions.CapitalizeRandomWordUsername;
|
||||
@@ -807,12 +791,9 @@ namespace Bit.App.Pages
|
||||
TriggerPropertyChanged(nameof(PlusAddressedEmailTypeSelected));
|
||||
TriggerPropertyChanged(nameof(IncludeNumberRandomWordUsername));
|
||||
TriggerPropertyChanged(nameof(CapitalizeRandomWordUsername));
|
||||
TriggerPropertyChanged(nameof(SimpleLoginApiKey));
|
||||
TriggerPropertyChanged(nameof(FirefoxRelayApiAccessToken));
|
||||
TriggerPropertyChanged(nameof(ForwardedEmailApiSecret));
|
||||
TriggerPropertyChanged(nameof(ForwardedEmailApiSecretLabel));
|
||||
TriggerPropertyChanged(nameof(AnonAddyDomainName));
|
||||
TriggerPropertyChanged(nameof(AnonAddyApiAccessToken));
|
||||
TriggerPropertyChanged(nameof(DuckDuckGoApiKey));
|
||||
TriggerPropertyChanged(nameof(FastmailApiKey));
|
||||
TriggerPropertyChanged(nameof(CatchAllEmailDomain));
|
||||
TriggerPropertyChanged(nameof(ForwardedEmailServiceSelected));
|
||||
TriggerPropertyChanged(nameof(UsernameTypeSelected));
|
||||
@@ -827,7 +808,7 @@ namespace Bit.App.Pages
|
||||
private void SetOptions()
|
||||
{
|
||||
_options.AllowAmbiguousChar = AllowAmbiguousChars;
|
||||
_options.Type = PasswordTypeSelectedIndex == 1 ? "passphrase" : "password";
|
||||
_options.Type = PasswordTypeSelectedIndex == 1 ? PasswordGenerationOptions.TYPE_PASSPHRASE : PasswordGenerationOptions.TYPE_PASSWORD;
|
||||
_options.MinNumber = MinNumber;
|
||||
_options.MinSpecial = MinSpecial;
|
||||
_options.Special = Special;
|
||||
@@ -845,15 +826,23 @@ namespace Bit.App.Pages
|
||||
{
|
||||
_logger.Value.Exception(ex);
|
||||
|
||||
string message = AppResources.GenericErrorMessage;
|
||||
|
||||
if (IsUsername && UsernameTypeSelected == UsernameType.ForwardedEmailAlias)
|
||||
{
|
||||
await Device.InvokeOnMainThreadAsync(() => Page.DisplayAlert(
|
||||
AppResources.AnErrorHasOccurred, string.Format(AppResources.UnknownXErrorMessage, ForwardedEmailServiceSelected), AppResources.Ok));
|
||||
}
|
||||
else
|
||||
{
|
||||
await Device.InvokeOnMainThreadAsync(() => Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.GenericErrorMessage, AppResources.Ok));
|
||||
if (ex is ForwardedEmailInvalidSecretException)
|
||||
{
|
||||
message = ForwardedEmailServiceSelected == ForwardedEmailServiceType.AnonAddy || ForwardedEmailServiceSelected == ForwardedEmailServiceType.FirefoxRelay
|
||||
? AppResources.InvalidAPIToken
|
||||
: AppResources.InvalidAPIKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = string.Format(AppResources.UnknownXErrorMessage, ForwardedEmailServiceSelected);
|
||||
}
|
||||
}
|
||||
|
||||
await Device.InvokeOnMainThreadAsync(() => Page.DisplayAlert(AppResources.AnErrorHasOccurred, message, AppResources.Ok));
|
||||
}
|
||||
|
||||
private string GetUsernameTypeLabelDescription(UsernameType value)
|
||||
@@ -870,27 +859,5 @@ namespace Bit.App.Pages
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ToggleForwardedEmailHiddenValueAsync()
|
||||
{
|
||||
switch (ForwardedEmailServiceSelected)
|
||||
{
|
||||
case ForwardedEmailServiceType.AnonAddy:
|
||||
ShowAnonAddyApiAccessToken = !ShowAnonAddyApiAccessToken;
|
||||
break;
|
||||
case ForwardedEmailServiceType.FirefoxRelay:
|
||||
ShowFirefoxRelayApiAccessToken = !ShowFirefoxRelayApiAccessToken;
|
||||
break;
|
||||
case ForwardedEmailServiceType.SimpleLogin:
|
||||
ShowSimpleLoginApiKey = !ShowSimpleLoginApiKey;
|
||||
break;
|
||||
case ForwardedEmailServiceType.DuckDuckGo:
|
||||
ShowDuckDuckGoApiKey = !ShowDuckDuckGoApiKey;
|
||||
break;
|
||||
case ForwardedEmailServiceType.Fastmail:
|
||||
ShowFastmailApiKey = !ShowFastmailApiKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@
|
||||
<Label
|
||||
Text="{u:I18n SendDisabledWarning}"
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="SendDisabledWarningMessageLabel" />
|
||||
</Frame>
|
||||
<Frame
|
||||
IsVisible="{Binding SendOptionsPolicyInEffect}"
|
||||
@@ -83,7 +84,8 @@
|
||||
<Label
|
||||
Text="{u:I18n SendOptionsPolicyInEffect}"
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="SendOptionsPolicyInEffectLabel" />
|
||||
</Frame>
|
||||
<StackLayout StyleClass="box-row">
|
||||
<Label
|
||||
@@ -93,7 +95,8 @@
|
||||
x:Name="_nameEntry"
|
||||
Text="{Binding Send.Name}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="SendNameEntry" />
|
||||
<Label
|
||||
Text="{u:I18n NameInfo}"
|
||||
StyleClass="box-footer-label"
|
||||
@@ -123,6 +126,7 @@
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n File}"
|
||||
AutomationProperties.HelpText="{Binding FileTypeAccessibilityLabel}"
|
||||
AutomationId="SendFileButton"
|
||||
Grid.Column="0">
|
||||
</Button>
|
||||
<Button
|
||||
@@ -135,6 +139,7 @@
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Text}"
|
||||
AutomationProperties.HelpText="{Binding TextTypeAccessibilityLabel}"
|
||||
AutomationId="SendTextButton"
|
||||
Grid.Column="1">
|
||||
</Button>
|
||||
</Grid>
|
||||
@@ -152,12 +157,14 @@
|
||||
Text="{Binding Send.File.FileName, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalOptions="StartAndExpand" />
|
||||
HorizontalOptions="StartAndExpand"
|
||||
AutomationId="SendFileNameLabel" />
|
||||
<Label
|
||||
Text="{Binding Send.File.SizeName, Mode=OneWay}"
|
||||
StyleClass="box-sub-label"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="SendFileSizeLabel" />
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
IsVisible="{Binding EditMode, Converter={StaticResource inverseBool}}"
|
||||
@@ -168,20 +175,23 @@
|
||||
LineBreakMode="CharacterWrap"
|
||||
StyleClass="text-sm, text-muted"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="SendNoFileChosenLabel" />
|
||||
<Label
|
||||
IsVisible="{Binding FileName, Converter={StaticResource notNull}}"
|
||||
Text="{Binding FileName}"
|
||||
LineBreakMode="CharacterWrap"
|
||||
StyleClass="text-sm, text-muted"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="SendCurrentFileNameLabel" />
|
||||
<Button
|
||||
Text="{u:I18n ChooseFile}"
|
||||
IsVisible="{Binding IsAddFromShare, Converter={StaticResource inverseBool}}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-button-row"
|
||||
Clicked="ChooseFile_Clicked" />
|
||||
Clicked="ChooseFile_Clicked"
|
||||
AutomationId="SendChooseFileButton" />
|
||||
<Label
|
||||
Margin="0, 5, 0, 0"
|
||||
Text="{u:I18n MaxFileSize}"
|
||||
@@ -207,7 +217,8 @@
|
||||
Text="{Binding Send.Text.Text}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-value"
|
||||
Margin="{Binding EditorMargins}"
|
||||
Margin="{Binding EditorMargins}"
|
||||
AutomationId="SendTextContentEntry"
|
||||
effects:ScrollEnabledEffect.IsScrollEnabled="false" >
|
||||
<Editor.Behaviors>
|
||||
<behaviors:EditorPreventAutoBottomScrollingOnFocusedBehavior ParentScrollView="{x:Reference _scrollView}" />
|
||||
@@ -235,7 +246,8 @@
|
||||
IsToggled="{Binding Send.Text.Hidden}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
HorizontalOptions="End"
|
||||
Margin="10,0,0,0" />
|
||||
Margin="10,0,0,0"
|
||||
AutomationId="SendHideTextByDefaultToggle" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
@@ -249,7 +261,8 @@
|
||||
IsToggled="{Binding ShareOnSave}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
HorizontalOptions="End"
|
||||
Margin="10,0,0,0" />
|
||||
Margin="10,0,0,0"
|
||||
AutomationId="SendShareSendAfterSaveToggle" />
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
Orientation="Horizontal"
|
||||
@@ -263,21 +276,24 @@
|
||||
StyleClass="box-row-button"
|
||||
TextColor="{DynamicResource PrimaryColor}"
|
||||
Margin="0"
|
||||
AutomationProperties.IsInAccessibleTree="False"/>
|
||||
AutomationProperties.IsInAccessibleTree="False"
|
||||
AutomationId="SendShowHideOptionsButton" />
|
||||
<controls:IconButton
|
||||
x:Name="_btnOptionsUp"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.ChevronUp}}"
|
||||
StyleClass="box-row-button"
|
||||
TextColor="{DynamicResource PrimaryColor}"
|
||||
IsVisible="{Binding ShowOptions}"
|
||||
AutomationProperties.IsInAccessibleTree="False"/>
|
||||
AutomationProperties.IsInAccessibleTree="False"
|
||||
AutomationId="SendOptionsDisplayed" />
|
||||
<controls:IconButton
|
||||
x:Name="_btnOptionsDown"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.AngleDown}}"
|
||||
StyleClass="box-row-button"
|
||||
TextColor="{DynamicResource PrimaryColor}"
|
||||
IsVisible="{Binding ShowOptions, Converter={StaticResource inverseBool}}"
|
||||
AutomationProperties.IsInAccessibleTree="False"/>
|
||||
AutomationProperties.IsInAccessibleTree="False"
|
||||
AutomationId="SendOptionsHidden" />
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding ShowOptions}">
|
||||
<StackLayout
|
||||
@@ -294,7 +310,8 @@
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n DeletionTime}" />
|
||||
AutomationProperties.Name="{u:I18n DeletionTime}"
|
||||
AutomationId="SendDeletionOptionsPicker" />
|
||||
<Grid
|
||||
IsVisible="{Binding ShowDeletionCustomPickers}"
|
||||
Margin="0,5,0,0">
|
||||
@@ -308,14 +325,16 @@
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n DeletionDate}"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="SendCustomDeletionDatePicker" />
|
||||
<controls:ExtendedTimePicker
|
||||
NullableTime="{Binding DeletionDateTimeViewModel.Time, Mode=TwoWay}"
|
||||
Format="t"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n DeletionTime}"
|
||||
Grid.Column="1" />
|
||||
Grid.Column="1"
|
||||
AutomationId="SendCustomDeletionTimePicker" />
|
||||
</Grid>
|
||||
<Label
|
||||
Text="{u:I18n DeletionDateInfo}"
|
||||
@@ -334,7 +353,8 @@
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ExpirationTime}" />
|
||||
AutomationProperties.Name="{u:I18n ExpirationTime}"
|
||||
AutomationId="SendExpirationOptionsPicker" />
|
||||
<Grid
|
||||
IsVisible="{Binding ShowExpirationCustomPickers}"
|
||||
Margin="0,5,0,0">
|
||||
@@ -349,7 +369,8 @@
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ExpirationDate}"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="SendCustomExpirationDatePicker" />
|
||||
<controls:ExtendedTimePicker
|
||||
NullableTime="{Binding ExpirationDateTimeViewModel.Time, Mode=TwoWay}"
|
||||
PlaceHolder="--:-- --"
|
||||
@@ -357,7 +378,8 @@
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ExpirationTime}"
|
||||
Grid.Column="1" />
|
||||
Grid.Column="1"
|
||||
AutomationId="SendCustomExpirationTimePicker" />
|
||||
</Grid>
|
||||
<StackLayout
|
||||
Orientation="Horizontal"
|
||||
@@ -374,7 +396,8 @@
|
||||
FontSize="{Binding SegmentedButtonFontSize}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-row-button"
|
||||
Clicked="ClearExpirationDate_Clicked" />
|
||||
Clicked="ClearExpirationDate_Clicked"
|
||||
AutomationId="SendClearExpirationDateButton" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
@@ -393,13 +416,15 @@
|
||||
Keyboard="Numeric"
|
||||
MaxLength="9"
|
||||
TextChanged="OnMaxAccessCountTextChanged"
|
||||
HorizontalOptions="FillAndExpand" />
|
||||
HorizontalOptions="FillAndExpand"
|
||||
AutomationId="SendMaxAccessCountEntry" />
|
||||
<controls:ExtendedStepper
|
||||
x:Name="_maxAccessCountStepper"
|
||||
Value="{Binding MaxAccessCount}"
|
||||
Maximum="999999999"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
Margin="10,0,0,0" />
|
||||
Margin="10,0,0,0"
|
||||
AutomationId="SendMaxAccessCountStepper" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n MaximumAccessCountInfo}"
|
||||
@@ -419,7 +444,8 @@
|
||||
<Label
|
||||
Text="{Binding Send.AccessCount, Mode=OneWay}"
|
||||
StyleClass="box-label"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="SendCurrentAccessCountLabel" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
@@ -436,7 +462,8 @@
|
||||
StyleClass="box-value"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False"
|
||||
HorizontalOptions="FillAndExpand" />
|
||||
HorizontalOptions="FillAndExpand"
|
||||
AutomationId="SendNewPasswordEntry" />
|
||||
<controls:IconButton
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
@@ -445,7 +472,8 @@
|
||||
Margin="10,0,0,0"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}" />
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
|
||||
AutomationId="SendShowHidePasswordButton" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n PasswordInfo}"
|
||||
@@ -464,7 +492,8 @@
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
StyleClass="box-value"
|
||||
Margin="{Binding EditorMargins}"
|
||||
effects:ScrollEnabledEffect.IsScrollEnabled="false" >
|
||||
effects:ScrollEnabledEffect.IsScrollEnabled="false"
|
||||
AutomationId="SendNotesEntry">
|
||||
<Editor.Behaviors>
|
||||
<behaviors:EditorPreventAutoBottomScrollingOnFocusedBehavior ParentScrollView="{x:Reference _scrollView}" />
|
||||
</Editor.Behaviors>
|
||||
@@ -492,7 +521,8 @@
|
||||
IsToggled="{Binding Send.HideEmail}"
|
||||
IsEnabled="{Binding DisableHideEmailControl, Converter={StaticResource inverseBool}}"
|
||||
HorizontalOptions="End"
|
||||
Margin="10,0,0,0" />
|
||||
Margin="10,0,0,0"
|
||||
AutomationId="SendHideEmailSwitch" />
|
||||
</StackLayout>
|
||||
<StackLayout
|
||||
StyleClass="box-row, box-row-switch"
|
||||
@@ -506,7 +536,8 @@
|
||||
IsToggled="{Binding Send.Disabled}"
|
||||
IsEnabled="{Binding SendEnabled}"
|
||||
HorizontalOptions="End"
|
||||
Margin="10,0,0,0" />
|
||||
Margin="10,0,0,0"
|
||||
AutomationId="SendDeactivateSwitch" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
Priority="-2"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"
|
||||
AutomationId="AccountIconButton" />
|
||||
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1" x:Name="_closeItem" />
|
||||
<ToolbarItem Text="{u:I18n Save}" Clicked="Save_Clicked" Order="Primary" x:Name="_saveItem"/>
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
@@ -44,13 +44,15 @@
|
||||
<controls:SendViewCell
|
||||
Send="{Binding Send}"
|
||||
ButtonCommand="{Binding BindingContext.SendOptionsCommand, Source={x:Reference _page}}"
|
||||
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}" />
|
||||
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}"
|
||||
AutomationId="SendCell" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="sendGroupTemplate"
|
||||
x:DataType="pages:SendGroupingsPageListItem">
|
||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
StyleClass="list-row, list-row-platform"
|
||||
AutomationId="{Binding AutomationId}">
|
||||
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
@@ -64,12 +66,14 @@
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title" />
|
||||
StyleClass="list-title"
|
||||
AutomationId="SendFilterNameLabel" />
|
||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="list-sub" />
|
||||
StyleClass="list-sub"
|
||||
AutomationId="SendFilterCountLabel" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
|
||||
|
||||
@@ -66,5 +66,27 @@ namespace Bit.App.Pages
|
||||
return _icon;
|
||||
}
|
||||
}
|
||||
|
||||
public string AutomationId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_name != null)
|
||||
{
|
||||
return "SendItem";
|
||||
}
|
||||
if (Type != null)
|
||||
{
|
||||
switch (Type.Value)
|
||||
{
|
||||
case SendType.Text:
|
||||
return "SendTextFilter";
|
||||
case SendType.File:
|
||||
return "SendFileFilter";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,8 @@
|
||||
Margin="20, 0"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NoSendDisplayedLabel" />
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowList}"
|
||||
ItemsSource="{Binding Sends}"
|
||||
@@ -67,13 +68,15 @@
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform"
|
||||
ExtraDataForLogging="Sends Page">
|
||||
ExtraDataForLogging="Sends Page"
|
||||
AutomationId="SendCellList">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:SendView">
|
||||
<controls:SendViewCell
|
||||
Send="{Binding .}"
|
||||
ButtonCommand="{Binding BindingContext.SendOptionsCommand, Source={x:Reference _page}}"
|
||||
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}" />
|
||||
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}"
|
||||
AutomationId="SendCell" />
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</controls:ExtendedCollectionView>
|
||||
|
||||
@@ -13,8 +13,13 @@
|
||||
</ContentPage.BindingContext>
|
||||
|
||||
<ContentPage.ToolbarItems>
|
||||
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
|
||||
<ToolbarItem Text="{u:I18n Save}" Clicked="Save_Clicked" Order="Primary" />
|
||||
<ToolbarItem Text="{u:I18n Cancel}"
|
||||
Clicked="Close_Clicked"
|
||||
Order="Primary"
|
||||
Priority="-1" />
|
||||
<ToolbarItem Text="{u:I18n Save}"
|
||||
Clicked="Save_Clicked"
|
||||
Order="Primary" />
|
||||
<ToolbarItem Text="{u:I18n Delete}"
|
||||
Clicked="Delete_Clicked"
|
||||
Order="Secondary"
|
||||
@@ -43,7 +48,8 @@
|
||||
StyleClass="box-value"
|
||||
x:Name="_nameEntry"
|
||||
ReturnType="Go"
|
||||
ReturnCommand="{Binding SubmitCommand}" />
|
||||
ReturnCommand="{Binding SubmitCommand}"
|
||||
AutomationId="FolderNameEntry" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
Margin="20, 0"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NoFoldersLabel"></Label>
|
||||
<controls:ExtendedCollectionView
|
||||
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
|
||||
ItemsSource="{Binding Folders}"
|
||||
@@ -44,10 +45,12 @@
|
||||
<DataTemplate x:DataType="views:FolderView">
|
||||
<controls:ExtendedStackLayout
|
||||
StyleClass="list-row, list-row-platform"
|
||||
Padding="10">
|
||||
Padding="10"
|
||||
AutomationId="FolderCell">
|
||||
<Label LineBreakMode="TailTruncation"
|
||||
StyleClass="list-title, list-title-platform"
|
||||
Text="{Binding Name, Mode=OneWay}" />
|
||||
Text="{Binding Name, Mode=OneWay}"
|
||||
AutomationId="FolderName" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
x:Name="_themePicker"
|
||||
ItemsSource="{Binding ThemeOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding ThemeSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ThemeSelectorPicker" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
StyleClass="box-footer-label"
|
||||
@@ -44,7 +45,8 @@
|
||||
x:Name="_autoDarkThemePicker"
|
||||
ItemsSource="{Binding AutoDarkThemeOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding AutoDarkThemeSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="DefaultDarkThemePicker" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
StyleClass="box-footer-label"
|
||||
@@ -59,7 +61,8 @@
|
||||
x:Name="_uriMatchPicker"
|
||||
ItemsSource="{Binding UriMatchOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding UriMatchSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="DefaultUriMatchDetectionPicker" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n DefaultUriMatchDetectionDescription}"
|
||||
@@ -74,7 +77,8 @@
|
||||
x:Name="_clearClipboardPicker"
|
||||
ItemsSource="{Binding ClearClipboardOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding ClearClipboardSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ClearClipboardPicker" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n ClearClipboardDescription}"
|
||||
@@ -90,7 +94,8 @@
|
||||
ItemsSource="{Binding LocalesOptions, Mode=OneTime}"
|
||||
SelectedItem="{Binding SelectedLocale}"
|
||||
ItemDisplayBinding="{Binding Value}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="LanguagePicker" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n LanguageChangeRequiresAppRestart}"
|
||||
@@ -105,7 +110,8 @@
|
||||
<Switch
|
||||
IsToggled="{Binding AutoTotpCopy}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="CopyTotpAutomaticallyToggle" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n CopyTotpAutomaticallyDescription}"
|
||||
@@ -120,7 +126,8 @@
|
||||
<Switch
|
||||
IsToggled="{Binding Favicon}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="ShowWebsiteIconsToggle" />
|
||||
</StackLayout>
|
||||
<Label
|
||||
Text="{u:I18n ShowWebsiteIconsDescription}"
|
||||
|
||||
@@ -32,19 +32,21 @@
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
HorizontalTextAlignment="Center" />
|
||||
</Frame>
|
||||
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
|
||||
<controls:CustomLabel IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
|
||||
Text="{Binding Name, Mode=OneWay}"
|
||||
LineBreakMode="{Binding LineBreakMode}"
|
||||
HorizontalOptions="StartAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title"/>
|
||||
<Label Text="{Binding SubLabel, Mode=OneWay}"
|
||||
StyleClass="list-title"
|
||||
AutomationId="{Binding AutomationIdSettingName}" />
|
||||
<controls:CustomLabel Text="{Binding SubLabel, Mode=OneWay}"
|
||||
IsVisible="{Binding ShowSubLabel}"
|
||||
HorizontalOptions="End"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
TextColor="{Binding SubLabelColor}"
|
||||
StyleClass="list-sub" />
|
||||
StyleClass="list-sub"
|
||||
AutomationId="{Binding AutomationIdSettingStatus}" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
<DataTemplate
|
||||
@@ -57,7 +59,8 @@
|
||||
Padding="10"
|
||||
HasShadow="False"
|
||||
BackgroundColor="Transparent"
|
||||
BorderColor="{DynamicResource PrimaryColor}">
|
||||
BorderColor="{DynamicResource PrimaryColor}"
|
||||
AutomationId="SettingActivePolicyTextLabel">
|
||||
<Label
|
||||
Text="{Binding Name, Mode=OneWay}"
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
@@ -75,7 +78,8 @@
|
||||
VerticalOptions="Center"
|
||||
FontSize="Small"
|
||||
TextColor="{Binding SubLabelColor}"
|
||||
StyleClass="list-sub" Margin="-5"/>
|
||||
StyleClass="list-sub" Margin="-5"
|
||||
AutomationId="SettingCustomVaultTimeoutPicker" />
|
||||
<controls:ExtendedStackLayout.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="ActivateTimePicker"/>
|
||||
</controls:ExtendedStackLayout.GestureRecognizers>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.App.Utilities.Automation;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
@@ -22,5 +24,29 @@ namespace Bit.App.Pages
|
||||
public Color SubLabelColor => SubLabelTextEnabled ?
|
||||
ThemeManager.GetResourceColor("SuccessColor") :
|
||||
ThemeManager.GetResourceColor("MutedColor");
|
||||
|
||||
public string AutomationIdSettingName
|
||||
{
|
||||
get
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor(
|
||||
UseFrame ? "EnabledPolicy"
|
||||
: AutomationIdsHelper.ToEnglishTitleCase(Name)
|
||||
, SuffixType.Cell);
|
||||
}
|
||||
}
|
||||
|
||||
public string AutomationIdSettingStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UseFrame)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Name), SuffixType.SettingValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,7 @@ using Bit.App.Pages.Accounts;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Models.Response;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Utilities;
|
||||
using Xamarin.CommunityToolkit.ObjectModel;
|
||||
@@ -51,7 +48,7 @@ namespace Bit.App.Pages
|
||||
private bool _reportLoggingEnabled;
|
||||
private bool _approvePasswordlessLoginRequests;
|
||||
private bool _shouldConnectToWatch;
|
||||
private List<KeyValuePair<string, int?>> _vaultTimeouts =
|
||||
private readonly static List<KeyValuePair<string, int?>> VaultTimeoutOptions =
|
||||
new List<KeyValuePair<string, int?>>
|
||||
{
|
||||
new KeyValuePair<string, int?>(AppResources.Immediately, 0),
|
||||
@@ -65,7 +62,7 @@ namespace Bit.App.Pages
|
||||
new KeyValuePair<string, int?>(AppResources.Never, null),
|
||||
new KeyValuePair<string, int?>(AppResources.Custom, CustomVaultTimeoutValue),
|
||||
};
|
||||
private List<KeyValuePair<string, VaultTimeoutAction>> _vaultTimeoutActions =
|
||||
private readonly static List<KeyValuePair<string, VaultTimeoutAction>> VaultTimeoutActionOptions =
|
||||
new List<KeyValuePair<string, VaultTimeoutAction>>
|
||||
{
|
||||
new KeyValuePair<string, VaultTimeoutAction>(AppResources.Lock, VaultTimeoutAction.Lock),
|
||||
@@ -74,6 +71,8 @@ namespace Bit.App.Pages
|
||||
|
||||
private Policy _vaultTimeoutPolicy;
|
||||
private int? _vaultTimeout;
|
||||
private List<KeyValuePair<string, int?>> _vaultTimeoutOptions = VaultTimeoutOptions;
|
||||
private List<KeyValuePair<string, VaultTimeoutAction>> _vaultTimeoutActionOptions = VaultTimeoutActionOptions;
|
||||
|
||||
public SettingsPageViewModel()
|
||||
{
|
||||
@@ -117,20 +116,28 @@ namespace Bit.App.Pages
|
||||
_localizeService.GetLocaleShortTime(lastSync.Value));
|
||||
}
|
||||
|
||||
_vaultTimeoutPolicy = null;
|
||||
_vaultTimeoutOptions = VaultTimeoutOptions;
|
||||
_vaultTimeoutActionOptions = VaultTimeoutActionOptions;
|
||||
|
||||
_vaultTimeout = await _vaultTimeoutService.GetVaultTimeout();
|
||||
_vaultTimeoutDisplayValue = _vaultTimeoutOptions.FirstOrDefault(o => o.Value == _vaultTimeout).Key;
|
||||
_vaultTimeoutDisplayValue ??= _vaultTimeoutOptions.Where(o => o.Value == CustomVaultTimeoutValue).First().Key;
|
||||
|
||||
var action = await _vaultTimeoutService.GetVaultTimeoutAction() ?? VaultTimeoutAction.Lock;
|
||||
_vaultTimeoutActionDisplayValue = _vaultTimeoutActionOptions.FirstOrDefault(o => o.Value == action).Key;
|
||||
|
||||
if (await _policyService.PolicyAppliesToUser(PolicyType.MaximumVaultTimeout))
|
||||
{
|
||||
// if we have a vault timeout policy, we need to filter the timeout options
|
||||
_vaultTimeoutPolicy = (await _policyService.GetAll(PolicyType.MaximumVaultTimeout)).First();
|
||||
var minutes = _policyService.GetPolicyInt(_vaultTimeoutPolicy, "minutes").GetValueOrDefault();
|
||||
_vaultTimeouts = _vaultTimeouts.Where(t =>
|
||||
t.Value <= minutes &&
|
||||
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
||||
_vaultTimeoutOptions = _vaultTimeoutOptions.Where(t =>
|
||||
t.Value <= policyMinutes &&
|
||||
(t.Value > 0 || t.Value == CustomVaultTimeoutValue) &&
|
||||
t.Value != null).ToList();
|
||||
}
|
||||
|
||||
_vaultTimeout = await _vaultTimeoutService.GetVaultTimeout();
|
||||
_vaultTimeoutDisplayValue = _vaultTimeouts.FirstOrDefault(o => o.Value == _vaultTimeout).Key;
|
||||
var action = await _stateService.GetVaultTimeoutActionAsync() ?? VaultTimeoutAction.Lock;
|
||||
_vaultTimeoutActionDisplayValue = _vaultTimeoutActions.FirstOrDefault(o => o.Value == action).Key;
|
||||
var pinSet = await _vaultTimeoutService.IsPinLockSetAsync();
|
||||
_pin = pinSet.Item1 || pinSet.Item2;
|
||||
_biometric = await _vaultTimeoutService.IsBiometricLockSetAsync();
|
||||
@@ -266,7 +273,7 @@ namespace Bit.App.Pages
|
||||
{
|
||||
var oldTimeout = _vaultTimeout;
|
||||
|
||||
var options = _vaultTimeouts.Select(
|
||||
var options = _vaultTimeoutOptions.Select(
|
||||
o => o.Key == _vaultTimeoutDisplayValue ? $"✓ {o.Key}" : o.Key).ToArray();
|
||||
if (promptOptions)
|
||||
{
|
||||
@@ -277,7 +284,7 @@ namespace Bit.App.Pages
|
||||
return;
|
||||
}
|
||||
var cleanSelection = selection.Replace("✓ ", string.Empty);
|
||||
var selectionOption = _vaultTimeouts.FirstOrDefault(o => o.Key == cleanSelection);
|
||||
var selectionOption = _vaultTimeoutOptions.FirstOrDefault(o => o.Key == cleanSelection);
|
||||
|
||||
// Check if the selected Timeout action is "Never" and if it's different from the previous selected value
|
||||
if (selectionOption.Value == null && selectionOption.Value != oldTimeout)
|
||||
@@ -295,13 +302,13 @@ namespace Bit.App.Pages
|
||||
|
||||
if (_vaultTimeoutPolicy != null)
|
||||
{
|
||||
var maximumTimeout = _policyService.GetPolicyInt(_vaultTimeoutPolicy, "minutes");
|
||||
var maximumTimeout = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
||||
|
||||
if (newTimeout > maximumTimeout)
|
||||
{
|
||||
await _platformUtilsService.ShowDialogAsync(AppResources.VaultTimeoutToLarge, AppResources.Warning);
|
||||
var timeout = await _vaultTimeoutService.GetVaultTimeout();
|
||||
_vaultTimeoutDisplayValue = _vaultTimeouts.FirstOrDefault(o => o.Value == timeout).Key ??
|
||||
_vaultTimeoutDisplayValue = _vaultTimeoutOptions.FirstOrDefault(o => o.Value == timeout).Key ??
|
||||
AppResources.Custom;
|
||||
return;
|
||||
}
|
||||
@@ -374,7 +381,13 @@ namespace Bit.App.Pages
|
||||
|
||||
public async Task VaultTimeoutActionAsync()
|
||||
{
|
||||
var options = _vaultTimeoutActions.Select(o =>
|
||||
if (_vaultTimeoutPolicy != null &&
|
||||
!string.IsNullOrEmpty(_vaultTimeoutPolicy.GetString(Policy.ACTION_KEY)))
|
||||
{
|
||||
// do nothing if we have a policy set
|
||||
return;
|
||||
}
|
||||
var options = _vaultTimeoutActionOptions.Select(o =>
|
||||
o.Key == _vaultTimeoutActionDisplayValue ? $"✓ {o.Key}" : o.Key).ToArray();
|
||||
var selection = await Page.DisplayActionSheet(AppResources.VaultTimeoutAction,
|
||||
AppResources.Cancel, null, options);
|
||||
@@ -393,7 +406,7 @@ namespace Bit.App.Pages
|
||||
cleanSelection = AppResources.Lock;
|
||||
}
|
||||
}
|
||||
var selectionOption = _vaultTimeoutActions.FirstOrDefault(o => o.Key == cleanSelection);
|
||||
var selectionOption = _vaultTimeoutActionOptions.FirstOrDefault(o => o.Key == cleanSelection);
|
||||
var changed = _vaultTimeoutActionDisplayValue != selectionOption.Key;
|
||||
_vaultTimeoutActionDisplayValue = selectionOption.Key;
|
||||
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(_vaultTimeout,
|
||||
@@ -597,14 +610,36 @@ namespace Bit.App.Pages
|
||||
}
|
||||
if (_vaultTimeoutPolicy != null)
|
||||
{
|
||||
var maximumTimeout = _policyService.GetPolicyInt(_vaultTimeoutPolicy, "minutes").GetValueOrDefault();
|
||||
securityItems.Insert(0, new SettingsPageListItem
|
||||
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
||||
var policyAction = _vaultTimeoutPolicy.GetString(Policy.ACTION_KEY);
|
||||
|
||||
if (policyMinutes.HasValue || !string.IsNullOrWhiteSpace(policyAction))
|
||||
{
|
||||
Name = string.Format(AppResources.VaultTimeoutPolicyInEffect,
|
||||
Math.Floor((float)maximumTimeout / 60),
|
||||
maximumTimeout % 60),
|
||||
UseFrame = true,
|
||||
});
|
||||
string policyAlert;
|
||||
if (policyMinutes.HasValue && string.IsNullOrWhiteSpace(policyAction))
|
||||
{
|
||||
policyAlert = string.Format(AppResources.VaultTimeoutPolicyInEffect,
|
||||
Math.Floor((float)policyMinutes / 60),
|
||||
policyMinutes % 60);
|
||||
}
|
||||
else if (!policyMinutes.HasValue && !string.IsNullOrWhiteSpace(policyAction))
|
||||
{
|
||||
policyAlert = string.Format(AppResources.VaultTimeoutActionPolicyInEffect,
|
||||
policyAction == Policy.ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
policyAlert = string.Format(AppResources.VaultTimeoutPolicyWithActionInEffect,
|
||||
Math.Floor((float)policyMinutes / 60),
|
||||
policyMinutes % 60,
|
||||
policyAction == Policy.ACTION_LOCK ? AppResources.Lock : AppResources.LogOut);
|
||||
}
|
||||
securityItems.Insert(0, new SettingsPageListItem
|
||||
{
|
||||
Name = policyAlert,
|
||||
UseFrame = true,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (Device.RuntimePlatform == Device.Android)
|
||||
{
|
||||
@@ -792,12 +827,12 @@ namespace Bit.App.Pages
|
||||
|
||||
private VaultTimeoutAction GetVaultTimeoutActionFromKey(string key)
|
||||
{
|
||||
return _vaultTimeoutActions.FirstOrDefault(o => o.Key == key).Value;
|
||||
return _vaultTimeoutActionOptions.FirstOrDefault(o => o.Key == key).Value;
|
||||
}
|
||||
|
||||
private int? GetVaultTimeoutFromKey(string key)
|
||||
{
|
||||
return _vaultTimeouts.FirstOrDefault(o => o.Key == key).Value;
|
||||
return _vaultTimeoutOptions.FirstOrDefault(o => o.Key == key).Value;
|
||||
}
|
||||
|
||||
private string CreateSelectableOption(string option, bool selected) => selected ? $"✓ {option}" : option;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
||||
using Bit.App.Effects;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
@@ -15,6 +16,7 @@ namespace Bit.App.Pages
|
||||
private readonly IBroadcasterService _broadcasterService;
|
||||
private readonly IMessagingService _messagingService;
|
||||
private readonly IKeyConnectorService _keyConnectorService;
|
||||
private readonly IStateService _stateService;
|
||||
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
||||
|
||||
private NavigationPage _groupingsPage;
|
||||
@@ -26,6 +28,7 @@ namespace Bit.App.Pages
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
||||
_stateService = ServiceContainer.Resolve<IStateService>();
|
||||
|
||||
_groupingsPage = new NavigationPage(new GroupingsPage(true, previousPage: previousPage))
|
||||
{
|
||||
@@ -95,6 +98,13 @@ namespace Bit.App.Pages
|
||||
{
|
||||
_messagingService.Send("convertAccountToKeyConnector");
|
||||
}
|
||||
|
||||
var forcePasswordResetReason = await _stateService.GetForcePasswordResetReasonAsync();
|
||||
|
||||
if (forcePasswordResetReason.HasValue)
|
||||
{
|
||||
_messagingService.Send(Constants.ForceUpdatePassword);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDisappearing()
|
||||
|
||||
@@ -33,23 +33,25 @@
|
||||
<StackLayout StyleClass="box">
|
||||
<StackLayout StyleClass="box-row" Padding="10, 20"
|
||||
IsVisible="{Binding HasAttachments, Converter={StaticResource inverseBool}}">
|
||||
<Label Text="{u:I18n NoAttachments}" HorizontalTextAlignment="Center" />
|
||||
<Label Text="{u:I18n NoAttachments}" HorizontalTextAlignment="Center" AutomationId="NoAttachmentsLabel" />
|
||||
</StackLayout>
|
||||
<controls:RepeaterView ItemsSource="{Binding Attachments}" IsVisible="{Binding HasAttachments}">
|
||||
<controls:RepeaterView ItemsSource="{Binding Attachments}" IsVisible="{Binding HasAttachments}" AutomationId="AttachmentsList">
|
||||
<controls:RepeaterView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:AttachmentView">
|
||||
<StackLayout Spacing="0" Padding="0">
|
||||
<StackLayout Orientation="Horizontal" StyleClass="box-row" Spacing="10">
|
||||
<StackLayout Orientation="Horizontal" StyleClass="box-row" Spacing="10" AutomationId="AttachmentRow">
|
||||
<Label
|
||||
Text="{Binding FileName, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalOptions="StartAndExpand" />
|
||||
HorizontalOptions="StartAndExpand"
|
||||
AutomationId="AttachmentFileNameLabel" />
|
||||
<Label
|
||||
Text="{Binding SizeName, Mode=OneWay}"
|
||||
StyleClass="box-sub-label"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="AttachmentFileSizeLabel" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
|
||||
@@ -57,7 +59,8 @@
|
||||
CommandParameter="{Binding .}"
|
||||
VerticalOptions="Center"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Delete}" />
|
||||
AutomationProperties.Name="{u:I18n Delete}"
|
||||
AutomationId="AttachmentDeleteButton" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
@@ -77,17 +80,20 @@
|
||||
LineBreakMode="CharacterWrap"
|
||||
StyleClass="text-sm, text-muted"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NoFileChosenLabel" />
|
||||
<Label
|
||||
IsVisible="{Binding FileName, Converter={StaticResource notNull}}"
|
||||
Text="{Binding FileName}"
|
||||
LineBreakMode="CharacterWrap"
|
||||
StyleClass="text-sm, text-muted"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NewAttachmentNameLabel" />
|
||||
</StackLayout>
|
||||
<Button Text="{u:I18n ChooseFile}" StyleClass="box-button-row"
|
||||
Clicked="ChooseFile_Clicked"></Button>
|
||||
Clicked="ChooseFile_Clicked"
|
||||
AutomationId="ChooseFileButton"></Button>
|
||||
<Label
|
||||
Margin="0, 10, 0, 0"
|
||||
Text="{u:I18n MaxFileSize}"
|
||||
|
||||
@@ -57,16 +57,16 @@
|
||||
x:Key="deleteItem" />
|
||||
|
||||
<DataTemplate x:Key="TextCustomFieldDataTemplate">
|
||||
<il:TextCustomFieldItemLayout />
|
||||
<il:TextCustomFieldItemLayout AutomationId="TextCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="BooleanCustomFieldDataTemplate">
|
||||
<il:BooleanCustomFieldItemLayout />
|
||||
<il:BooleanCustomFieldItemLayout AutomationId="BooleanCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="HiddenCustomFieldDataTemplate">
|
||||
<il:HiddenCustomFieldItemLayout />
|
||||
<il:HiddenCustomFieldItemLayout AutomationId="HiddenCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="LinkedCustomFieldDataTemplate">
|
||||
<il:LinkedCustomFieldItemLayout />
|
||||
<il:LinkedCustomFieldItemLayout AutomationId="LinkedCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
|
||||
<dts:CustomFieldItemTemplateSelector x:Key="CustomFieldItemTemplateSelector"
|
||||
@@ -100,7 +100,8 @@
|
||||
<Label
|
||||
Text="{u:I18n PersonalOwnershipPolicyInEffect}"
|
||||
StyleClass="text-muted, text-sm, text-bold"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="PersonalOwnershipPolicyLabel"/>
|
||||
</Frame>
|
||||
</Grid>
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
@@ -116,7 +117,8 @@
|
||||
x:Name="_typePicker"
|
||||
ItemsSource="{Binding TypeOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding TypeSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemTypePicker" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -125,7 +127,10 @@
|
||||
<Entry
|
||||
x:Name="_nameEntry"
|
||||
Text="{Binding Cipher.Name}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Name}"
|
||||
AutomationId="ItemNameEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsLogin}" Spacing="0" Padding="0">
|
||||
<Grid StyleClass="box-row, box-row-input"
|
||||
@@ -138,7 +143,10 @@
|
||||
x:Name="_loginUsernameEntry"
|
||||
Text="{Binding Cipher.Login.Username}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"/>
|
||||
Grid.Row="1"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Username}"
|
||||
AutomationId="LoginUsernameEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Generate}}"
|
||||
@@ -146,7 +154,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n GenerateUsername}" />
|
||||
AutomationProperties.Name="{u:I18n GenerateUsername}"
|
||||
AutomationId="GenerateUsernameButton" />
|
||||
</Grid>
|
||||
<Grid StyleClass="box-row, box-row-input">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -174,7 +183,10 @@
|
||||
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False"
|
||||
IsEnabled="{Binding Cipher.ViewPassword}"/>
|
||||
IsEnabled="{Binding Cipher.ViewPassword}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Password}"
|
||||
AutomationId="LoginPasswordEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.CheckCircle}}"
|
||||
@@ -184,7 +196,8 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CheckPassword}"
|
||||
IsVisible="{Binding Cipher.ViewPassword}" />
|
||||
IsVisible="{Binding Cipher.ViewPassword}"
|
||||
AutomationId="CheckPasswordButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -195,7 +208,8 @@
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
|
||||
IsVisible="{Binding Cipher.ViewPassword}" />
|
||||
IsVisible="{Binding Cipher.ViewPassword}"
|
||||
AutomationId="ViewPasswordButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Generate}}"
|
||||
@@ -205,7 +219,8 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n GeneratePassword}"
|
||||
IsVisible="{Binding Cipher.ViewPassword}" />
|
||||
IsVisible="{Binding Cipher.ViewPassword}"
|
||||
AutomationId="RegeneratePasswordButton" />
|
||||
</Grid>
|
||||
|
||||
<Grid StyleClass="box-row, box-row-input">
|
||||
@@ -241,7 +256,8 @@
|
||||
Padding="0,15"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="FillAndExpand"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="SetupTotpButton" />
|
||||
</Frame>
|
||||
<controls:MonoEntry
|
||||
x:Name="_loginTotpEntry"
|
||||
@@ -254,7 +270,10 @@
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="{Binding TotpColumnSpan}" />
|
||||
Grid.ColumnSpan="{Binding TotpColumnSpan}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n AuthenticatorKey}"
|
||||
AutomationId="LoginTotpEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -262,7 +281,10 @@
|
||||
IsVisible="{Binding HasTotpValue}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2" />
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyTotp}"
|
||||
AutomationId="CopyTotpValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Camera}}"
|
||||
@@ -272,7 +294,8 @@
|
||||
Grid.RowSpan="2"
|
||||
IsVisible="{Binding HasTotpValue}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ScanQrTitle}" />
|
||||
AutomationProperties.Name="{u:I18n ScanQrTitle}"
|
||||
/>
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsCard}" Spacing="0" Padding="0">
|
||||
@@ -283,7 +306,8 @@
|
||||
<Entry
|
||||
x:Name="_cardholderNameEntry"
|
||||
Text="{Binding Cipher.Card.CardholderName}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="CardholderNameEntry" />
|
||||
</StackLayout>
|
||||
<Grid StyleClass="box-row, box-row-input">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -307,7 +331,10 @@
|
||||
Grid.Column="0"
|
||||
IsPassword="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False" />
|
||||
IsTextPredictionEnabled="False"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Number}"
|
||||
AutomationId="CardNumberEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowCardNumberIcon}"
|
||||
@@ -316,7 +343,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationId="ShowCardNumberButton" />
|
||||
</Grid>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -326,7 +354,8 @@
|
||||
x:Name="_cardBrandPicker"
|
||||
ItemsSource="{Binding CardBrandOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding CardBrandSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="CardBrandPicker" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -336,7 +365,8 @@
|
||||
x:Name="_cardExpMonthPicker"
|
||||
ItemsSource="{Binding CardExpMonthOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding CardExpMonthSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="CardExpirationMonthPicker" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -346,7 +376,10 @@
|
||||
x:Name="_cardExpYearEntry"
|
||||
Text="{Binding Cipher.Card.ExpYear}"
|
||||
StyleClass="box-value"
|
||||
Keyboard="Numeric" />
|
||||
Keyboard="Numeric"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ExpirationYear}"
|
||||
AutomationId="CardExpirationYearEntry" />
|
||||
</StackLayout>
|
||||
<Grid StyleClass="box-row, box-row-input">
|
||||
<Grid.RowDefinitions>
|
||||
@@ -371,7 +404,10 @@
|
||||
Keyboard="Numeric"
|
||||
IsPassword="{Binding ShowCardCode, Converter={StaticResource inverseBool}}"
|
||||
IsSpellCheckEnabled="False"
|
||||
IsTextPredictionEnabled="False" />
|
||||
IsTextPredictionEnabled="False"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n SecurityCode}"
|
||||
AutomationId="CardSecurityCodeEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowCardCodeIcon}"
|
||||
@@ -380,7 +416,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationId="CardShowSecurityCodeButton" />
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsIdentity}" Spacing="0" Padding="0">
|
||||
@@ -392,7 +429,8 @@
|
||||
x:Name="_identityTitlePicker"
|
||||
ItemsSource="{Binding IdentityTitleOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding IdentityTitleSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityTitlePicker" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -401,7 +439,10 @@
|
||||
<Entry
|
||||
x:Name="_identityFirstNameEntry"
|
||||
Text="{Binding Cipher.Identity.FirstName}"
|
||||
StyleClass="box-value,capitalize-word-input"/>
|
||||
StyleClass="box-value,capitalize-word-input"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n FirstName}"
|
||||
AutomationId="IdentityFirstNameEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -410,7 +451,10 @@
|
||||
<Entry
|
||||
x:Name="_identityMiddleNameEntry"
|
||||
Text="{Binding Cipher.Identity.MiddleName}"
|
||||
StyleClass="box-value,capitalize-word-input" />
|
||||
StyleClass="box-value,capitalize-word-input"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n MiddleName}"
|
||||
AutomationId="IdentityMiddleNameEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -419,7 +463,10 @@
|
||||
<Entry
|
||||
x:Name="_identityLastNameEntry"
|
||||
Text="{Binding Cipher.Identity.LastName}"
|
||||
StyleClass="box-value,capitalize-word-input" />
|
||||
StyleClass="box-value,capitalize-word-input"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n LastName}"
|
||||
AutomationId="IdentityLastNameEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -428,7 +475,10 @@
|
||||
<Entry
|
||||
x:Name="_identityUsernameEntry"
|
||||
Text="{Binding Cipher.Identity.Username}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Username}"
|
||||
AutomationId="IdentityUsernameEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -437,7 +487,10 @@
|
||||
<Entry
|
||||
x:Name="_identityCompanyEntry"
|
||||
Text="{Binding Cipher.Identity.Company}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Company}"
|
||||
AutomationId="IdentityCompanyEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -446,7 +499,10 @@
|
||||
<Entry
|
||||
x:Name="_identitySsnEntry"
|
||||
Text="{Binding Cipher.Identity.SSN}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n SSN}"
|
||||
AutomationId="IdentitySsnEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -455,7 +511,10 @@
|
||||
<Entry
|
||||
x:Name="_identityPassportNumberEntry"
|
||||
Text="{Binding Cipher.Identity.PassportNumber}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n PassportNumber}"
|
||||
AutomationId="IdentityPassportNumberEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -464,7 +523,10 @@
|
||||
<Entry
|
||||
x:Name="_identityLicenseNumberEntry"
|
||||
Text="{Binding Cipher.Identity.LicenseNumber}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n LicenseNumber}"
|
||||
AutomationId="IdentityLicenseNumberEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -474,7 +536,10 @@
|
||||
x:Name="_identityEmailEntry"
|
||||
Keyboard="Email"
|
||||
Text="{Binding Cipher.Identity.Email}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Email}"
|
||||
AutomationId="IdentityEmailEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -484,7 +549,10 @@
|
||||
x:Name="_identityPhoneEntry"
|
||||
Text="{Binding Cipher.Identity.Phone}"
|
||||
Keyboard="Telephone"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Phone}"
|
||||
AutomationId="IdentityPhoneEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -493,7 +561,10 @@
|
||||
<Entry
|
||||
x:Name="_identityAddress1Entry"
|
||||
Text="{Binding Cipher.Identity.Address1}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Address1}"
|
||||
AutomationId="IdentityAddressOneEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -502,7 +573,10 @@
|
||||
<Entry
|
||||
x:Name="_identityAddress2Entry"
|
||||
Text="{Binding Cipher.Identity.Address2}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Address2}"
|
||||
AutomationId="IdentityAddressTwoEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -511,7 +585,10 @@
|
||||
<Entry
|
||||
x:Name="_identityAddress3Entry"
|
||||
Text="{Binding Cipher.Identity.Address3}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Address3}"
|
||||
AutomationId="IdentityAddressThreeEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -520,7 +597,10 @@
|
||||
<Entry
|
||||
x:Name="_identityCityEntry"
|
||||
Text="{Binding Cipher.Identity.City}"
|
||||
StyleClass="box-value,capitalize-sentence-input" />
|
||||
StyleClass="box-value,capitalize-sentence-input"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CityTown}"
|
||||
AutomationId="IdentityCityEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -529,7 +609,10 @@
|
||||
<Entry
|
||||
x:Name="_identityStateEntry"
|
||||
Text="{Binding Cipher.Identity.State}"
|
||||
StyleClass="box-value,capitalize-sentence-input" />
|
||||
StyleClass="box-value,capitalize-sentence-input"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n StateProvince}"
|
||||
AutomationId="IdentityStateEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -538,7 +621,10 @@
|
||||
<Entry
|
||||
x:Name="_identityPostalCodeEntry"
|
||||
Text="{Binding Cipher.Identity.PostalCode}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ZipPostalCode}"
|
||||
AutomationId="IdentityPostalCodeEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -547,7 +633,10 @@
|
||||
<Entry
|
||||
x:Name="_identityCountryEntry"
|
||||
Text="{Binding Cipher.Identity.Country}"
|
||||
StyleClass="box-value,capitalize-sentence-input" />
|
||||
StyleClass="box-value,capitalize-sentence-input"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Country}"
|
||||
AutomationId="IdentityCountryEntry" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
@@ -559,7 +648,7 @@
|
||||
<controls:RepeaterView ItemsSource="{Binding Uris}">
|
||||
<controls:RepeaterView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:LoginUriView">
|
||||
<Grid StyleClass="box-row, box-row-input">
|
||||
<Grid StyleClass="box-row, box-row-input" AutomationId="UriListGrid" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -578,7 +667,10 @@
|
||||
Keyboard="Url"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n URI}"
|
||||
AutomationId="LoginUriEntry" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
|
||||
@@ -588,13 +680,15 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Options}" />
|
||||
AutomationProperties.Name="{u:I18n Options}"
|
||||
AutomationId="LoginUriOptionsButton" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</controls:RepeaterView.ItemTemplate>
|
||||
</controls:RepeaterView>
|
||||
<Button Text="{u:I18n NewUri}" StyleClass="box-button-row"
|
||||
Clicked="NewUri_Clicked"></Button>
|
||||
Clicked="NewUri_Clicked"
|
||||
AutomationId="LoginAddNewUriButton"></Button>
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box">
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
@@ -609,7 +703,8 @@
|
||||
x:Name="_folderPicker"
|
||||
ItemsSource="{Binding FolderOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding FolderSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="FolderPicker" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
<Label
|
||||
@@ -619,7 +714,8 @@
|
||||
<Switch
|
||||
IsToggled="{Binding Cipher.Favorite}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="ItemFavoriteToggle" />
|
||||
</StackLayout>
|
||||
<StackLayout x:Name="_passwordPrompt" StyleClass="box-row, box-row-switch">
|
||||
<Label
|
||||
@@ -631,13 +727,14 @@
|
||||
Command="{Binding PasswordPromptHelpCommand}"
|
||||
TextColor="{DynamicResource MutedColor}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.Name="{u:I18n MasterPasswordRePromptHelp}"
|
||||
HorizontalOptions="StartAndExpand" />
|
||||
<Switch
|
||||
IsToggled="{Binding PasswordPrompt}"
|
||||
Toggled="PasswordPrompt_Toggled"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="MasterPasswordRepromptToggle" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
@@ -652,7 +749,10 @@
|
||||
AutoSize="TextChanges"
|
||||
StyleClass="box-value"
|
||||
effects:ScrollEnabledEffect.IsScrollEnabled="false"
|
||||
Text="{Binding Cipher.Notes}">
|
||||
Text="{Binding Cipher.Notes}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Notes}"
|
||||
AutomationId="ItemNotesEntry">
|
||||
<Editor.Behaviors>
|
||||
<behaviors:EditorPreventAutoBottomScrollingOnFocusedBehavior ParentScrollView="{x:Reference _scrollView}" />
|
||||
</Editor.Behaviors>
|
||||
@@ -671,9 +771,11 @@
|
||||
<StackLayout
|
||||
Spacing="0"
|
||||
BindableLayout.ItemsSource="{Binding Fields}"
|
||||
BindableLayout.ItemTemplateSelector="{StaticResource CustomFieldItemTemplateSelector}" />
|
||||
BindableLayout.ItemTemplateSelector="{StaticResource CustomFieldItemTemplateSelector}"
|
||||
AutomationId="CustomFieldsList" />
|
||||
<Button Text="{u:I18n NewCustomField}" StyleClass="box-button-row"
|
||||
Clicked="NewField_Clicked"></Button>
|
||||
Clicked="NewField_Clicked"
|
||||
AutomationId="NewCustomFieldButton"></Button>
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box" IsVisible="{Binding ShowOwnershipOptions}">
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
@@ -688,7 +790,8 @@
|
||||
x:Name="_ownershipPicker"
|
||||
ItemsSource="{Binding OwnershipOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding OwnershipSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemOwnershipPicker" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box" IsVisible="{Binding ShowCollections}">
|
||||
@@ -699,7 +802,8 @@
|
||||
<StackLayout Spacing="0" Padding="0"
|
||||
IsVisible="{Binding HasCollections, Converter={StaticResource inverseBool}}">
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
<Label Text="{u:I18n NoCollectionsToList}" />
|
||||
<Label Text="{u:I18n NoCollectionsToList}"
|
||||
AutomationId="NoCollectionsToListLabel" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
@@ -709,15 +813,17 @@
|
||||
<controls:RepeaterView.ItemTemplate>
|
||||
<DataTemplate x:DataType="pages:CollectionViewModel">
|
||||
<StackLayout Spacing="0" Padding="0">
|
||||
<StackLayout StyleClass="box-row, box-row-switch">
|
||||
<StackLayout StyleClass="box-row, box-row-switch" AutomationId="CollectionItemCell">
|
||||
<Label
|
||||
Text="{Binding Collection.Name}"
|
||||
StyleClass="box-label-regular"
|
||||
HorizontalOptions="StartAndExpand" />
|
||||
HorizontalOptions="StartAndExpand"
|
||||
AutomationId="CollectionItemNameLabel" />
|
||||
<Switch
|
||||
IsToggled="{Binding Checked}"
|
||||
StyleClass="box-value"
|
||||
HorizontalOptions="End" />
|
||||
HorizontalOptions="End"
|
||||
AutomationId="CollectionItemSwitch" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
@@ -727,5 +833,4 @@
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
||||
@@ -49,16 +49,16 @@
|
||||
x:Name="_cloneItem" x:Key="cloneItem" />
|
||||
|
||||
<DataTemplate x:Key="TextCustomFieldDataTemplate">
|
||||
<il:TextCustomFieldItemLayout />
|
||||
<il:TextCustomFieldItemLayout AutomationId="TextCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="BooleanCustomFieldDataTemplate">
|
||||
<il:BooleanCustomFieldItemLayout />
|
||||
<il:BooleanCustomFieldItemLayout AutomationId="BooleanCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="HiddenCustomFieldDataTemplate">
|
||||
<il:HiddenCustomFieldItemLayout />
|
||||
<il:HiddenCustomFieldItemLayout AutomationId="HiddenCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="LinkedCustomFieldDataTemplate">
|
||||
<il:LinkedCustomFieldItemLayout />
|
||||
<il:LinkedCustomFieldItemLayout AutomationId="LinkedCustomFieldItem" />
|
||||
</DataTemplate>
|
||||
|
||||
<dts:CustomFieldItemTemplateSelector x:Key="CustomFieldItemTemplateSelector"
|
||||
@@ -69,23 +69,26 @@
|
||||
|
||||
<ScrollView x:Key="scrollView" x:Name="_scrollView">
|
||||
<StackLayout Spacing="20" x:Name="_mainLayout">
|
||||
<StackLayout StyleClass="box">
|
||||
<StackLayout StyleClass="box" AutomationId="ItemInformationSection">
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
<Label Text="{u:I18n ItemInformation, Header=True}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row">
|
||||
<StackLayout StyleClass="box-row" AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Name}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Name, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
<StackLayout IsVisible="{Binding IsLogin}" Spacing="0" Padding="0">
|
||||
<Grid StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Login.Username, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Login.Username, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -98,12 +101,14 @@
|
||||
Text="{u:I18n Username}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Login.Username, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -113,12 +118,14 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyUsername}" />
|
||||
AutomationProperties.Name="{u:I18n CopyUsername}"
|
||||
AutomationId="CopyValueButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Login.Username, Converter={StaticResource stringHasValue}}" />
|
||||
<Grid StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Login.Password, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Login.Password, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -133,20 +140,23 @@
|
||||
Text="{u:I18n Password}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ItemName" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Cipher.Login.MaskedPassword, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding ShowPassword, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding ColoredPassword, Mode=OneWay}"
|
||||
StyleClass="box-value, text-html"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
LineBreakMode="CharacterWrap"
|
||||
IsVisible="{Binding ShowPassword}" />
|
||||
IsVisible="{Binding ShowPassword}"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.CheckCircle}}"
|
||||
@@ -156,7 +166,8 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CheckPassword}"
|
||||
IsVisible="{Binding Cipher.ViewPassword}" />
|
||||
IsVisible="{Binding Cipher.ViewPassword}"
|
||||
AutomationId="CheckPasswordButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowPasswordIcon}"
|
||||
@@ -167,7 +178,8 @@
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationProperties.HelpText="{Binding PasswordVisibilityAccessibilityText}"
|
||||
IsVisible="{Binding Cipher.ViewPassword}" />
|
||||
IsVisible="{Binding Cipher.ViewPassword}"
|
||||
AutomationId="ViewValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -178,11 +190,14 @@
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyPassword}"
|
||||
IsVisible="{Binding Cipher.ViewPassword}" />
|
||||
IsVisible="{Binding Cipher.ViewPassword}"
|
||||
AutomationId="CopyValueButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Login.Password, Converter={StaticResource stringHasValue}}" />
|
||||
<Grid StyleClass="box-row" IsVisible="{Binding ShowTotp}">
|
||||
<Grid StyleClass="box-row"
|
||||
IsVisible="{Binding ShowTotp}"
|
||||
AutomationId="ItemRow">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -197,7 +212,8 @@
|
||||
Text="{u:I18n VerificationCodeTotp}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ItemName" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding TotpCodeFormatted, Mode=OneWay}"
|
||||
IsVisible="{Binding ShowUpgradePremiumTotpText, Converter={StaticResource inverseBool}}"
|
||||
@@ -205,14 +221,16 @@
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
VerticalTextAlignment="Start"
|
||||
VerticalOptions="Start" />
|
||||
VerticalOptions="Start"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:CircularProgressbarView
|
||||
Progress="{Binding TotpProgress}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="FillAndExpand" />
|
||||
VerticalOptions="FillAndExpand"
|
||||
AutomationId="LoginTotpProgressBar" />
|
||||
<Label
|
||||
Text="{Binding TotpSec, Mode=OneWay}"
|
||||
Style="{DynamicResource textTotp}"
|
||||
@@ -234,7 +252,8 @@
|
||||
Grid.Column="2"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyTotp}" />
|
||||
AutomationProperties.Name="{u:I18n CopyTotp}"
|
||||
AutomationId="CopyValueButton" />
|
||||
<Label
|
||||
Text="{u:I18n PremiumSubscriptionRequired}"
|
||||
StyleClass="box-footer-label"
|
||||
@@ -242,24 +261,29 @@
|
||||
Margin="0,5,0,2"
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
HorizontalOptions="FillAndExpand" />
|
||||
HorizontalOptions="FillAndExpand"
|
||||
AutomationId="ShowUpgradePremiumTotpLabel" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator" IsVisible="{Binding ShowTotp}" />
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsCard}" Spacing="0" Padding="0">
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Card.CardholderName, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Card.CardholderName, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n CardholderName}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Card.CardholderName, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Card.CardholderName, Converter={StaticResource stringHasValue}}" />
|
||||
<Grid StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Card.Number, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Card.Number, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -273,19 +297,22 @@
|
||||
Text="{u:I18n Number}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ItemName" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Cipher.Card.MaskedNumber, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Cipher.Card.Number, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding ShowCardNumber}" />
|
||||
IsVisible="{Binding ShowCardNumber}"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowCardNumberIcon}"
|
||||
@@ -294,7 +321,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationId="ShowValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -304,34 +332,42 @@
|
||||
Grid.Column="2"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopyNumber}" />
|
||||
AutomationProperties.Name="{u:I18n CopyNumber}"
|
||||
AutomationId="CopyValueButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Card.Number, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Card.Brand, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Card.Brand, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Brand}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Card.Brand, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Card.Brand, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Card.Expiration, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Card.Expiration, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Expiration}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Card.Expiration, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Card.Expiration, Converter={StaticResource stringHasValue}}" />
|
||||
<Grid StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Card.Code, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Card.Code, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -345,19 +381,22 @@
|
||||
Text="{u:I18n SecurityCode}"
|
||||
StyleClass="box-label"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="ItemName" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Cipher.Card.MaskedCode, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding ShowCardCode, Converter={StaticResource inverseBool}}" />
|
||||
IsVisible="{Binding ShowCardCode, Converter={StaticResource inverseBool}}"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Cipher.Card.Code, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
IsVisible="{Binding ShowCardCode}" />
|
||||
IsVisible="{Binding ShowCardCode}"
|
||||
AutomationId="ItemValue" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding ShowCardCodeIcon}"
|
||||
@@ -366,7 +405,8 @@
|
||||
Grid.Column="1"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationId="ShowValueButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -376,124 +416,156 @@
|
||||
Grid.Column="2"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n CopySecurityCode}" />
|
||||
AutomationProperties.Name="{u:I18n CopySecurityCode}"
|
||||
AutomationId="CopyValueButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Card.Code, Converter={StaticResource stringHasValue}}" />
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsIdentity}" Spacing="0" Padding="0">
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.FullName, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.FullName, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n IdentityName}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.FullName, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.FullName, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.Username, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.Username, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Username}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Username, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.Username, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.Company, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.Company, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Company}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Company, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.Company, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.SSN, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.SSN, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n SSN}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.SSN, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.SSN, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.PassportNumber, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.PassportNumber, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n PassportNumber}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.PassportNumber, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.PassportNumber, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.LicenseNumber, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.LicenseNumber, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n LicenseNumber}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.LicenseNumber, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.LicenseNumber, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.Email, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.Email, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Email}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Email, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.Email, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row"
|
||||
IsVisible="{Binding Cipher.Identity.Phone, Converter={StaticResource stringHasValue}}">
|
||||
IsVisible="{Binding Cipher.Identity.Phone, Converter={StaticResource stringHasValue}}"
|
||||
AutomationId="ItemRow" >
|
||||
<Label
|
||||
Text="{u:I18n Phone}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Phone, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemValue" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator"
|
||||
IsVisible="{Binding Cipher.Identity.Phone, Converter={StaticResource stringHasValue}}" />
|
||||
<StackLayout StyleClass="box-row" IsVisible="{Binding ShowIdentityAddress}">
|
||||
<StackLayout StyleClass="box-row" IsVisible="{Binding ShowIdentityAddress}"
|
||||
AutomationId="ItemRow">
|
||||
<Label
|
||||
Text="{u:I18n Address}"
|
||||
StyleClass="box-label" />
|
||||
StyleClass="box-label"
|
||||
AutomationId="ItemName" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Address1, Mode=OneWay}"
|
||||
IsVisible="{Binding Cipher.Identity.Address1, Converter={StaticResource stringHasValue}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityAddressOneLabel" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Address2, Mode=OneWay}"
|
||||
IsVisible="{Binding Cipher.Identity.Address2, Converter={StaticResource stringHasValue}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityAddressTwoLabel" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Address3, Mode=OneWay}"
|
||||
IsVisible="{Binding Cipher.Identity.Address3, Converter={StaticResource stringHasValue}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityAddressThreeLabel" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.FullAddressPart2, Mode=OneWay}"
|
||||
IsVisible="{Binding Cipher.Identity.FullAddressPart2, Converter={StaticResource stringHasValue}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityFullAddressPartTwoLabel" />
|
||||
<Label
|
||||
Text="{Binding Cipher.Identity.Country, Mode=OneWay}"
|
||||
IsVisible="{Binding Cipher.Identity.Country, Converter={StaticResource stringHasValue}}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="IdentityCountryLabel" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" IsVisible="{Binding ShowIdentityAddress}" />
|
||||
</StackLayout>
|
||||
@@ -503,11 +575,11 @@
|
||||
<Label Text="{u:I18n URIs, Header=True}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<controls:RepeaterView ItemsSource="{Binding Cipher.Login.Uris}">
|
||||
<controls:RepeaterView ItemsSource="{Binding Cipher.Login.Uris}" AutomationId="CipherUriContainer">
|
||||
<controls:RepeaterView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:LoginUriView">
|
||||
<StackLayout Spacing="0" Padding="0">
|
||||
<Grid StyleClass="box-row">
|
||||
<Grid StyleClass="box-row" AutomationId="UriRow">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
@@ -533,7 +605,8 @@
|
||||
Text="{Binding HostOrUri, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
Grid.Column="0"
|
||||
AutomationId="UriValue" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.ShareSquare}}"
|
||||
@@ -544,7 +617,8 @@
|
||||
Grid.RowSpan="2"
|
||||
IsVisible="{Binding CanLaunch, Mode=OneWay}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Launch}" />
|
||||
AutomationProperties.Name="{u:I18n Launch}"
|
||||
AutomationId="LaunchUriButton" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Clone}}"
|
||||
@@ -554,7 +628,8 @@
|
||||
Grid.Column="2"
|
||||
Grid.RowSpan="2"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Copy}" />
|
||||
AutomationProperties.Name="{u:I18n Copy}"
|
||||
AutomationId="CopyUriButton" />
|
||||
</Grid>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
@@ -568,14 +643,15 @@
|
||||
<Label Text="{u:I18n Notes, Header=True}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row">
|
||||
<StackLayout StyleClass="box-row" AutomationId="NotesRow">
|
||||
<controls:SelectableLabel
|
||||
Text="{Binding Cipher.Notes, Mode=OneWay}"
|
||||
StyleClass="box-value" />
|
||||
StyleClass="box-value"
|
||||
AutomationId="CipherNotesLabel" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box" IsVisible="{Binding Cipher.HasFields}">
|
||||
<StackLayout StyleClass="box" IsVisible="{Binding Cipher.HasFields}" AutomationId="CustomFieldsContainer">
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
<Label Text="{u:I18n CustomFields, Header=True}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
@@ -590,21 +666,23 @@
|
||||
<Label Text="{u:I18n Attachments, Header=True}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<controls:RepeaterView ItemsSource="{Binding Cipher.Attachments}">
|
||||
<controls:RepeaterView ItemsSource="{Binding Cipher.Attachments}" AutomationId="CipherAttachmentsContainer">
|
||||
<controls:RepeaterView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:AttachmentView">
|
||||
<StackLayout Spacing="0" Padding="0">
|
||||
<StackLayout Orientation="Horizontal" StyleClass="box-row" Spacing="10">
|
||||
<StackLayout Orientation="Horizontal" StyleClass="box-row" Spacing="10" AutomationId="CipherAttachment">
|
||||
<Label
|
||||
Text="{Binding FileName, Mode=OneWay}"
|
||||
StyleClass="box-value"
|
||||
VerticalTextAlignment="Center"
|
||||
HorizontalOptions="StartAndExpand" />
|
||||
HorizontalOptions="StartAndExpand"
|
||||
AutomationId="CipherAttachmentFileNameLabel" />
|
||||
<Label
|
||||
Text="{Binding SizeName, Mode=OneWay}"
|
||||
StyleClass="box-sub-label"
|
||||
HorizontalTextAlignment="End"
|
||||
VerticalTextAlignment="Center" />
|
||||
VerticalTextAlignment="Center"
|
||||
AutomationId="CipherAttachmentFileSizeLabel" />
|
||||
<controls:IconButton
|
||||
StyleClass="box-row-button, box-row-button-platform"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Download}}"
|
||||
@@ -612,7 +690,8 @@
|
||||
CommandParameter="{Binding .}"
|
||||
VerticalOptions="Center"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Download}" />
|
||||
AutomationProperties.Name="{u:I18n Download}"
|
||||
AutomationId="CipherAttachmentDownloadButton" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="box-row-separator" />
|
||||
</StackLayout>
|
||||
@@ -622,17 +701,20 @@
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-bottom">
|
||||
<Label FormattedText="{Binding UpdatedText}"
|
||||
StyleClass="box-footer-label" />
|
||||
StyleClass="box-footer-label"
|
||||
AutomationId="CipherUpdatedDateLabel" />
|
||||
<Label FormattedText="{Binding PasswordUpdatedText}"
|
||||
StyleClass="box-footer-label"
|
||||
IsVisible="{Binding Cipher.PasswordRevisionDisplayDate, Converter={StaticResource notNull}}">
|
||||
IsVisible="{Binding Cipher.PasswordRevisionDisplayDate, Converter={StaticResource notNull}}"
|
||||
AutomationId="CipherUpdatedPasswordDateLabel">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="PasswordHistory_Tapped" />
|
||||
</Label.GestureRecognizers>
|
||||
</Label>
|
||||
<Label FormattedText="{Binding PasswordHistoryText}"
|
||||
StyleClass="box-footer-label"
|
||||
IsVisible="{Binding Cipher.HasPasswordHistory}">
|
||||
IsVisible="{Binding Cipher.HasPasswordHistory}"
|
||||
AutomationId="CipherPasswordHistoryLabel">
|
||||
<Label.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="PasswordHistory_Tapped" />
|
||||
</Label.GestureRecognizers>
|
||||
@@ -662,6 +744,7 @@
|
||||
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n EditItem}"
|
||||
AutomationId="CipherEditButton"
|
||||
IsVisible="{Binding CanEdit}">
|
||||
<Button.Effects>
|
||||
<effects:FabShadowEffect />
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
IconImageSource="{Binding AvatarImageSource}"
|
||||
Command="{Binding Source={x:Reference _accountListOverlay}, Path=ToggleVisibililtyCommand}"
|
||||
Order="Primary"
|
||||
Priority="-2"
|
||||
Priority="-1"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"
|
||||
AutomationId="AccountIconButton" />
|
||||
<ToolbarItem IconImageSource="search.png" Clicked="Search_Clicked"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Search}" />
|
||||
|
||||
@@ -69,14 +69,16 @@ namespace Bit.App.Pages
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: There's currently an issue on iOS where the toolbar item is not getting updated
|
||||
// as the others somehow. Removing this so at least we get the circle with ".." instead
|
||||
// of a white circle
|
||||
if (Device.RuntimePlatform != Device.iOS)
|
||||
try
|
||||
{
|
||||
// don't crash the app if the avatar can't be loaded, just log the ex
|
||||
_accountAvatar?.OnAppearing();
|
||||
_vm.AvatarImageSource = await GetAvatarImageSourceAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
||||
}
|
||||
|
||||
_broadcasterService.Subscribe(nameof(CipherSelectionPage), async (message) =>
|
||||
{
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
HorizontalOptions="FillAndExpand"
|
||||
TextChanged="SearchBar_TextChanged"
|
||||
SearchButtonPressed="SearchBar_SearchButtonPressed"
|
||||
Placeholder="{Binding PageTitle}" />
|
||||
Placeholder="{Binding PageTitle}"
|
||||
AutomationId="SearchBar" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform"
|
||||
x:Name="_separator" x:Key="separator" />
|
||||
@@ -91,7 +92,8 @@
|
||||
Source="empty_items_state" />
|
||||
<Label
|
||||
Text="{u:I18n ThereAreNoItemsThatMatchTheSearch}"
|
||||
HorizontalTextAlignment="Center" />
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NoSearchResultsLabel" />
|
||||
<Button
|
||||
Text="{u:I18n AddAnItem}"
|
||||
Command="{Binding AddCipherCommand}"
|
||||
@@ -104,7 +106,8 @@
|
||||
SelectionMode="Single"
|
||||
SelectionChanged="RowSelected"
|
||||
StyleClass="list, list-platform"
|
||||
ExtraDataForLogging="Ciphers Page">
|
||||
ExtraDataForLogging="Ciphers Page"
|
||||
AutomationId="CipherList">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate x:DataType="views:CipherView">
|
||||
<controls:CipherViewCell
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
Priority="-1"
|
||||
UseOriginalImage="True"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Account}" />
|
||||
AutomationProperties.Name="{u:I18n Account}"
|
||||
AutomationId="AccountIconButton" />
|
||||
<ToolbarItem Icon="search.png" Clicked="Search_Clicked"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Search}" />
|
||||
@@ -59,13 +60,14 @@
|
||||
<controls:AuthenticatorViewCell
|
||||
Cipher="{Binding Cipher}"
|
||||
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
|
||||
TotpSec="{Binding TotpSec}"/>
|
||||
TotpSec="{Binding TotpSec}" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="groupTemplate"
|
||||
x:DataType="pages:GroupingsPageListItem">
|
||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
||||
StyleClass="list-row, list-row-platform">
|
||||
StyleClass="list-row, list-row-platform"
|
||||
AutomationId="{Binding AutomationId}">
|
||||
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
|
||||
HorizontalOptions="Start"
|
||||
VerticalOptions="Center"
|
||||
@@ -79,12 +81,14 @@
|
||||
LineBreakMode="TailTruncation"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
StyleClass="list-title"/>
|
||||
StyleClass="list-title"
|
||||
AutomationId="ItemNameLabel" />
|
||||
<Label Text="{Binding ItemCount, Mode=OneWay}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
HorizontalTextAlignment="End"
|
||||
StyleClass="list-sub"/>
|
||||
StyleClass="list-sub"
|
||||
AutomationId="ItemCountLabel" />
|
||||
</controls:ExtendedStackLayout>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -95,7 +99,8 @@
|
||||
Spacing="0"
|
||||
Padding="0"
|
||||
VerticalOptions="FillAndExpand"
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
||||
StyleClass="list-row-header-container, list-row-header-container-platform"
|
||||
AutomationId="{Binding AutomationId}">
|
||||
<BoxView
|
||||
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
|
||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
||||
@@ -104,7 +109,8 @@
|
||||
StyleClass="list-header, list-header-platform" />
|
||||
<Label
|
||||
Text="{Binding ItemCount}"
|
||||
StyleClass="list-header-sub" />
|
||||
StyleClass="list-header-sub"
|
||||
AutomationId="SectionItemCount" />
|
||||
</StackLayout>
|
||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
||||
</StackLayout>
|
||||
@@ -147,7 +153,8 @@
|
||||
IsVisible="{Binding ShowNoData}">
|
||||
<Label
|
||||
Text="{Binding NoDataText}"
|
||||
HorizontalTextAlignment="Center"></Label>
|
||||
HorizontalTextAlignment="Center"
|
||||
AutomationId="NoDataDisplayed"></Label>
|
||||
<Button
|
||||
Text="{u:I18n AddAnItem}"
|
||||
Clicked="AddButton_Clicked"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Bit.App.Pages
|
||||
using Bit.App.Utilities.Automation;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public class GroupingsPageHeaderListItem : IGroupingsPageListItem
|
||||
{
|
||||
@@ -10,5 +12,12 @@
|
||||
|
||||
public string Title { get; }
|
||||
public string ItemCount { get; set; }
|
||||
public string AutomationId
|
||||
{
|
||||
get
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor(AutomationIdsHelper.ToEnglishTitleCase(Title), SuffixType.Header);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Bit.App.Utilities.Automation;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
@@ -32,5 +33,6 @@ namespace Bit.App.Pages
|
||||
public string Name { get; set; }
|
||||
public string NameShort => string.IsNullOrWhiteSpace(Name) || Name.Length == 0 ? "-" : Name[0].ToString();
|
||||
public string ItemCount { get; set; }
|
||||
public string AutomationId => AutomationIdsHelper.AddSuffixFor(NameShort, SuffixType.ListGroup);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Utilities.Automation;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.View;
|
||||
@@ -115,5 +116,38 @@ namespace Bit.App.Pages
|
||||
return _icon;
|
||||
}
|
||||
}
|
||||
|
||||
public string AutomationId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Type != null)
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor(System.Enum.GetName(typeof(CipherType), Type.Value), SuffixType.Filter);
|
||||
}
|
||||
|
||||
if (IsTrash)
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor("Trash", SuffixType.Filter);
|
||||
}
|
||||
|
||||
if (Folder != null)
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor("Folder", SuffixType.Filter);
|
||||
}
|
||||
|
||||
if (Collection != null)
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor("Collection", SuffixType.Filter);
|
||||
}
|
||||
|
||||
if (IsTotpCode)
|
||||
{
|
||||
return AutomationIdsHelper.AddSuffixFor("TOTP", SuffixType.ListItem);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
161
src/App/Resources/AppResources.Designer.cs
generated
161
src/App/Resources/AppResources.Designer.cs
generated
@@ -202,6 +202,24 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Biometric unlock for this account is disabled pending verification of master password..
|
||||
/// </summary>
|
||||
public static string AccountBiometricInvalidated {
|
||||
get {
|
||||
return ResourceManager.GetString("AccountBiometricInvalidated", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Autofill biometric unlock for this account is disabled pending verification of master password..
|
||||
/// </summary>
|
||||
public static string AccountBiometricInvalidatedExtension {
|
||||
get {
|
||||
return ResourceManager.GetString("AccountBiometricInvalidatedExtension", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your new account has been created! You may now log in..
|
||||
/// </summary>
|
||||
@@ -967,24 +985,6 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Biometric unlock disabled pending verification of master password..
|
||||
/// </summary>
|
||||
public static string BiometricInvalidated {
|
||||
get {
|
||||
return ResourceManager.GetString("BiometricInvalidated", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Biometric unlock for autofill disabled pending verification of master password..
|
||||
/// </summary>
|
||||
public static string BiometricInvalidatedExtension {
|
||||
get {
|
||||
return ResourceManager.GetString("BiometricInvalidatedExtension", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Biometrics.
|
||||
/// </summary>
|
||||
@@ -1687,6 +1687,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Current master password.
|
||||
/// </summary>
|
||||
public static string CurrentMasterPassword {
|
||||
get {
|
||||
return ResourceManager.GetString("CurrentMasterPassword", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Custom.
|
||||
/// </summary>
|
||||
@@ -1741,6 +1750,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Data region.
|
||||
/// </summary>
|
||||
public static string DataRegion {
|
||||
get {
|
||||
return ResourceManager.GetString("DataRegion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Password updated.
|
||||
/// </summary>
|
||||
@@ -2317,6 +2335,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to EU.
|
||||
/// </summary>
|
||||
public static string EU {
|
||||
get {
|
||||
return ResourceManager.GetString("EU", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exact.
|
||||
/// </summary>
|
||||
@@ -3235,6 +3262,24 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid API key.
|
||||
/// </summary>
|
||||
public static string InvalidAPIKey {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidAPIKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid API token.
|
||||
/// </summary>
|
||||
public static string InvalidAPIToken {
|
||||
get {
|
||||
return ResourceManager.GetString("InvalidAPIToken", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Invalid email address..
|
||||
/// </summary>
|
||||
@@ -3560,11 +3605,11 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Logging in as {0}.
|
||||
/// Looks up a localized string similar to Logging in as {0} on {1}.
|
||||
/// </summary>
|
||||
public static string LoggingInAsX {
|
||||
public static string LoggingInAsXOnY {
|
||||
get {
|
||||
return ResourceManager.GetString("LoggingInAsX", resourceCulture);
|
||||
return ResourceManager.GetString("LoggingInAsXOnY", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3867,6 +3912,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Master password re-prompt help.
|
||||
/// </summary>
|
||||
public static string MasterPasswordRePromptHelp {
|
||||
get {
|
||||
return ResourceManager.GetString("MasterPasswordRePromptHelp", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Match detection.
|
||||
/// </summary>
|
||||
@@ -5120,6 +5174,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Region.
|
||||
/// </summary>
|
||||
public static string Region {
|
||||
get {
|
||||
return ResourceManager.GetString("Region", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remember me.
|
||||
/// </summary>
|
||||
@@ -5453,6 +5516,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Self-hosted.
|
||||
/// </summary>
|
||||
public static string SelfHosted {
|
||||
get {
|
||||
return ResourceManager.GetString("SelfHosted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Self-hosted environment.
|
||||
/// </summary>
|
||||
@@ -6380,6 +6452,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve..
|
||||
/// </summary>
|
||||
public static string UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve {
|
||||
get {
|
||||
return ResourceManager.GetString("UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unlock vault.
|
||||
/// </summary>
|
||||
@@ -6452,6 +6533,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour..
|
||||
/// </summary>
|
||||
public static string UpdateWeakMasterPasswordWarning {
|
||||
get {
|
||||
return ResourceManager.GetString("UpdateWeakMasterPasswordWarning", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Updating password.
|
||||
/// </summary>
|
||||
@@ -6506,6 +6596,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to US.
|
||||
/// </summary>
|
||||
public static string US {
|
||||
get {
|
||||
return ResourceManager.GetString("US", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use another two-step login method.
|
||||
/// </summary>
|
||||
@@ -6677,6 +6776,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your organization policies have set your vault timeout action to {0}..
|
||||
/// </summary>
|
||||
public static string VaultTimeoutActionPolicyInEffect {
|
||||
get {
|
||||
return ResourceManager.GetString("VaultTimeoutActionPolicyInEffect", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Logging out will remove all access to your vault and requires online authentication after the timeout period. Are you sure you want to use this setting?.
|
||||
/// </summary>
|
||||
@@ -6687,7 +6795,7 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s).
|
||||
/// Looks up a localized string similar to Your organization policies have set your maximum allowed vault timeout to {0} hour(s) and {1} minute(s)..
|
||||
/// </summary>
|
||||
public static string VaultTimeoutPolicyInEffect {
|
||||
get {
|
||||
@@ -6695,6 +6803,15 @@ namespace Bit.App.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}..
|
||||
/// </summary>
|
||||
public static string VaultTimeoutPolicyWithActionInEffect {
|
||||
get {
|
||||
return ResourceManager.GetString("VaultTimeoutPolicyWithActionInEffect", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Your vault timeout exceeds the restrictions set by your organization..
|
||||
/// </summary>
|
||||
|
||||
@@ -1752,11 +1752,11 @@ Skandering gebeur outomaties.</value>
|
||||
<value>Wil u dit regtig na die asblik stuur?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometriese ontgrendeling gedeaktiveer hangende bevestiging van hoofwagwoord.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometriese ontgrendeling vir hierdie rekening is gedeaktiveer hangende bevestiging van hoofwagwoord.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Biometriese ontgrendeling vir outovul gedeaktiveer hangende bevestiging van hoofwagwoord.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Outovul-biometriese ontgrendeline vir hierdie rekening is gedeaktiveer hangende bevestiging van hoofwagwoord.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Aktiveer sinchronisering by verfrissing</value>
|
||||
@@ -2142,6 +2142,12 @@ Skandering gebeur outomaties.</value>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>U organisasiebeleide beïnvloed u kluisuitelling. Maksimum toegelate kluisuittelling is {0} uur en {1} minuut(e).</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Jou organisasie se beleid affekteer jou kluis-uittel tyd. Maksimum toelaatbare kluis-uittel tyd is {0} uur(ure) en {1} minuut(minute). Jou kluis-uittel aksie is gestel na {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Jou organisasie se beleid het jou kluis-uittel aksie na {0} verander.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>U kluisuittelling oorskry die beperkinge wat deur u organisasie daargestel is.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@ Wil u na die rekening omskakel?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Kry hoofwagwoord wenk</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Teken in as {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Teken aan as {0} op {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Nie jy nie?</value>
|
||||
@@ -2592,15 +2598,48 @@ Wil u na die rekening omskakel?</value>
|
||||
<value>Organisasie SSO identifiseerder vereis.</value>
|
||||
</data>
|
||||
<data name="AddTheKeyToAnExistingOrNewItem" xml:space="preserve">
|
||||
<value>Add the key to an existing or new item</value>
|
||||
<value>Voeg die sleutel by 'n huidige of nuwe item</value>
|
||||
</data>
|
||||
<data name="ThereAreNoItemsInYourVaultThatMatchX" xml:space="preserve">
|
||||
<value>There are no items in your vault that match "{0}"</value>
|
||||
<value>Daar is geen items in jou kluis wat met "{0}" ooreenstem nie</value>
|
||||
</data>
|
||||
<data name="SearchForAnItemOrAddANewItem" xml:space="preserve">
|
||||
<value>Search for an item or add a new item</value>
|
||||
<value>Soek vir 'n item of voeg 'n nuwe een by</value>
|
||||
</data>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>There are no items that match the search</value>
|
||||
<value>Daar is geen items wat met die soekterm ooreenstem nie</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>VS</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>EU</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Selghehuisves</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Datastreek</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Streek</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>U hoofwagwoord voldoen nie aan een of meer van die organisasiebeleide nie. Om toegang tot die kluis te kry, moet u nou u hoofwagwoord bywerk. Deur voort te gaan sal u van u huidige sessie afgeteken word, en u sal weer moet aanteken. Aktiewe sessies op ander toestelle kan vir tot een uur aktief bly.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Huidige hoofwagwoord</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Master password re-prompt help</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Invalid API key</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Invalid API token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@
|
||||
<value>هل تريد حقاً أن ترسل إلى سلة المهملات؟</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>تم تعطيل فتح القفل الحيوي في انتظار التحقق من كلمة المرور الرئيسية.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>تم تعطيل فتح القفل الحيوي لهذا الحساب في انتظار التحقق من كلمة المرور الرئيسية.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>تم تعطيل إلغاء القفل البيومتري للملء التلقائي في انتظار التحقق من كلمة المرور الرئيسية.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>إلغاء القفل الحيوي للملء التلقائي لهذا الحساب معطل في انتظار التحقق من كلمة المرور الرئيسية.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>تمكين المزامنة عند التحديث</value>
|
||||
@@ -2143,6 +2143,12 @@
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>سياسات مؤسستك تؤثر على مهلة الخزنة الخاص بك. الحد الأقصى المسموح به لمهلة الخزنة هو {0} ساعة و {1} دقيقة</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>سياسات مؤسستك تؤثر على مهلة خزنتك. الحد الأقصى المسموح به لمهلة الخزنة هو {0} ساعة(ساعات) و {1} دقيقة(دقائق). يتم تعيين إجراء مهلة المخزن الخاص بك إلى {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>سياسات مؤسستك قامت بتعيين إجراء مهلة خزنتك إلى {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>مهلة خزنتك تتجاوز القيود التي تضعها مؤسستك.</value>
|
||||
</data>
|
||||
@@ -2490,8 +2496,8 @@
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>احصل على تلميح كلمة المرور الرئيسية</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>تسجيل الدخول كـ {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>تسجيل الدخول كـ {0} في {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>ليس أنت؟</value>
|
||||
@@ -2604,4 +2610,37 @@
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>لا توجد عناصر تطابق البحث</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>الولايات المتحدة</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>الاتحاد الأوروبي</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>استضافة ذاتية</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>منطقة البيانات</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>المنطقة</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>كلمة المرور الرئيسية الخاصة بك لا تفي بواحدة أو أكثر من سياسات مؤسستك. من أجل الوصول إلى الخزنة، يجب عليك تحديث كلمة المرور الرئيسية الآن. سيتم تسجيل خروجك من الجلسة الحالية، مما يتطلب منك تسجيل الدخول مرة أخرى. وقد تظل الجلسات النشطة على أجهزة أخرى نشطة لمدة تصل إلى ساعة واحدة.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>كلمة المرور الرئيسية الحالية</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Master password re-prompt help</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Invalid API key</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Invalid API token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<value>Həqiqətən tullantı qutusuna göndərmək istəyirsiniz?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Ana parolun təsdiqlənməsi gözlənildiyi üçün biometrik kilid açma sıradan çıxarıldı.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Ana parolun təsdiqlənməsi gözlənildiyi üçün bu hesab üzrə biometrik kilid açma sıradan çıxarıldı.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Ana parolun təsdiqlənməsi gözlənildiyi üçün avto-doldurma üzrə biometrik kilid açma sıradan çıxarıldı.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Ana parolun təsdiqlənməsi gözlənildiyi üçün bu hesab üzrə avto-doldurma biometrik kilid açma sıradan çıxarıldı.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Təzələmə əsnasında eyniləşdirməni fəallaşdır</value>
|
||||
@@ -2142,6 +2142,12 @@ Skan prosesi avtomatik baş tutacaq.</value>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Təşkilatınızın siyasətləri, anbarınızın vaxt bitişinə təsir edir. Anbar vaxt bitişi üçün icazə verilən maksimum vaxt {0} saat {1} dəqiqədir</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Təşkilatınızın siyasətləri, anbarınızın vaxt bitişinə təsir edir. Anbar vaxt bitişi üçün icazə verilən maksimum vaxt {0} saat {1} dəqiqədir. Anbar vaxt bitişi əməliyyatı {2} olaraq tənzimləndi.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Təşkilatınızın siyasətləri, anbar vaxt bitişi əməliyyatınızı {0} olaraq tənzimlədi.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Anbar vaxt bitişi, təşkilatınız tərəfindən tənzimlənən məhdudiyyətləri aşır.</value>
|
||||
</data>
|
||||
@@ -2488,8 +2494,8 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Ana parol üçün məsləhət alın</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>{0} olaraq giriş edilir</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>{1} üzərində {0} olaraq giriş edildi</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Siz deyilsiniz?</value>
|
||||
@@ -2602,4 +2608,37 @@ Bu hesaba keçmək istəyirsiniz?</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>Axtarışa uyğun gələn heç bir element yoxdur</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>ABŞ</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>AB</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Öz-özünə sahiblik edən</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Data bölgəsi</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Bölgə</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Ana parolunuz təşkilatınızdakı siyasətlərdən birinə və ya bir neçəsinə uyğun gəlmir. Anbara müraciət üçün ana parolunuzu indi güncəlləməlisiniz. Davam etsəniz, hazırkı seansdan çıxış etmiş və təkrar giriş etməli olacaqsınız. Digər cihazlardakı aktiv seanslar bir saata qədər aktiv qalmağa davam edə bilər.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Hazırkı ana parol</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Ana parolu təkrar soruş köməyi</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Yetərsiz yaddaşa görə kilid açma uğursuz ola bilər. Həll etmək üçün KDF yaddaş tənzimləmələrinizi azaldın</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Yararsız API açarı</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Yararsız API tokeni</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1751,11 +1751,11 @@
|
||||
<value>Вы сапраўды хочаце адправіць элемент у сметніцу?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Разблакіраванне па біяметрыі адключана. Чакаецца праверка асноўным паролем.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Разблакіроўка па біяметрыі для гэтага ўліковага запісу адключана. Чакаецца праверка асноўным паролем.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Разблакіраванне па біяметрыі для аўтазапаўнення адключана. Чакаецца праверка асноўным паролем.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Аўтазапаўненне з дапамогай разблакіроўкі па біяметрыі для гэтага ўліковага запісу адключана. Чакаецца праверка асноўным паролем.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Уключыць сінхранізацыю пры абнаўленні</value>
|
||||
@@ -2142,6 +2142,12 @@
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Палітыка вашай арганізацыі ўплывае на час чакання сховішча. Максімальны дазволены час чакання сховішча складае {0} гадз. і {1} хв.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Палітыка вашай арганізацыі ўплывае на час чакання сховішча. Максімальны дазволены час чакання сховішча складае гадзін: {0}; хвілін: {1}. Для часу чакання вашага сховішча прызначана дзеянне {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Палітыкай вашай арганізацыі прызначана дзеянне {0} для часу чакання вашага сховішча.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Час чакання вашага сховішча перавышае дазволеныя абмежаванні, якія прызначыла ваша арганізацыя.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Атрымаць падказку да асноўнага пароля</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Увайсці як {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Вы ўваходзіце як {0} у {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Не вы?</value>
|
||||
@@ -2603,4 +2609,37 @@
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>Адсутнічаюць элементы, якія адпавядаюць пошуку</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>ЗША</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>ЕС</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Уласнае размяшчэнне</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Рэгіён даных</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Рэгіён</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Ваш асноўны пароль не адпавядае адной або некалькім палітыкам арганізацыі. Для атрымання доступу да сховішча, вы павінны абнавіць яго. Працягваючы, вы выйдзіце з бягучага сеанса і вам неабходна будзе ўвайсці паўторна. Актыўныя сеансы на іншых прыладах могуць заставацца актыўнымі на працягу адной гадзіны.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Бягучы асноўны пароль</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Дапамога з паўторным запытам асноўнага пароля</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Па прычыне недахопу памяці можа адбыцца збой разблакіроўкі. Паменшыце налады памяці KDF, каб вырашыць гэту праблему</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Памылковы ключ API</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Памылковы токен API</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@
|
||||
<value>Сигурни ли сте, че искате да преместите записа в кошчето?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Засечена е промяна в биометричните данни. Впишете се с главната парола, за да я включите отново биометричната идентификация.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Потвърждаването с биометрични данни е изключено за тази регистрация. Въведете главната парола, за да го включите.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Потвърждаването с биометрични данни е изключено. Въведете главната парола, за да го включите.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Автоматичното попълване за потвърждаване с биометрични данни е изключено за тази регистрация. Въведете главната парола, за да го включите.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Синхронизация при опресняване</value>
|
||||
@@ -2142,6 +2142,12 @@
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Настройките на организацията Ви влияят върху времето за достъп до трезора Ви. Максималното разрешено време за достъп е {0} час(а) и {1} минути</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Настройките на организацията Ви влияят върху времето за достъп до трезора Ви. Максималното разрешено време за достъп е {0} час(а) и {1} минута/и. Зададеното действие при изтичане на това време е {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Настройките на организацията Ви задават следното действие при изтичане на времето за достъп до трезора: {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Времето за достъп до трезора Ви превишава ограничението, определено от организацията Ви.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@ select Add TOTP to store the key safely</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Получете подсказване за главната парола</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Вписване като {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Влизате като {0} в {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Това не сте Вие?</value>
|
||||
@@ -2603,4 +2609,37 @@ select Add TOTP to store the key safely</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>Няма елементи, които отговарят на търсенето</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>САЩ</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>ЕС</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Собствен хостинг</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Регион на данните</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Регион</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Вашата главна парола не отговаря на една или повече политики на организацията Ви. За да получите достъп до трезора, трябва да промените главната си парола сега. Това означава, че ще бъдете отписан(а) от текущата си сесия и ще трябва да се впишете отново. Активните сесии на други устройства може да продължат да бъдат активни още един час.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Текуща главна парола</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Помощ за повторното запитване за главната парола</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Отключването може да бъде неуспешно заради недостатъчно памет. Намалете настройките на паметта за KDF, за да разрешите проблема.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Неправилен ключ за ППИ</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Неправилен идентификатор за ППИ</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
<comment>The button text that allows a user to copy the login's username to their clipboard.</comment>
|
||||
</data>
|
||||
<data name="Credits" xml:space="preserve">
|
||||
<value>Credits</value>
|
||||
<value>কৃতিত্ব</value>
|
||||
<comment>Title for page that we use to give credit to resources that we use.</comment>
|
||||
</data>
|
||||
<data name="Delete" xml:space="preserve">
|
||||
@@ -168,11 +168,11 @@
|
||||
<comment>Delete an entity (verb).</comment>
|
||||
</data>
|
||||
<data name="Deleting" xml:space="preserve">
|
||||
<value>Deleting...</value>
|
||||
<value>মোছা হচ্ছে...</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="DoYouReallyWantToDelete" xml:space="preserve">
|
||||
<value>Do you really want to delete? This cannot be undone.</value>
|
||||
<value>আপনি কি সত্যিই মুছে ফেলতে চান? এটিকে পূর্বের মত করা যাবে না।.</value>
|
||||
<comment>Confirmation alert message when deleteing something.</comment>
|
||||
</data>
|
||||
<data name="Edit" xml:space="preserve">
|
||||
@@ -190,16 +190,16 @@
|
||||
<comment>Full label for a email address.</comment>
|
||||
</data>
|
||||
<data name="EmailUs" xml:space="preserve">
|
||||
<value>Email us</value>
|
||||
<value>আমাদের ইমেইল করুন</value>
|
||||
</data>
|
||||
<data name="EmailUsDescription" xml:space="preserve">
|
||||
<value>Email us directly to get help or leave feedback.</value>
|
||||
<value>সাহায্য পেতে বা মতামত দিতে সরাসরি আমাদের ইমেল করুন।</value>
|
||||
</data>
|
||||
<data name="EnterPIN" xml:space="preserve">
|
||||
<value>Enter your PIN code.</value>
|
||||
<value>আপনার পিন কোডটি প্রবেশ করান</value>
|
||||
</data>
|
||||
<data name="Favorites" xml:space="preserve">
|
||||
<value>Favorites</value>
|
||||
<value>পছন্দসমূহ</value>
|
||||
<comment>Title for your favorite items in the vault.</comment>
|
||||
</data>
|
||||
<data name="FileBugReport" xml:space="preserve">
|
||||
@@ -216,7 +216,7 @@
|
||||
<comment>Label for a folder.</comment>
|
||||
</data>
|
||||
<data name="FolderCreated" xml:space="preserve">
|
||||
<value>New folder created.</value>
|
||||
<value>নতুন ফোল্ডার তৈরি হয়েছে।</value>
|
||||
</data>
|
||||
<data name="FolderDeleted" xml:space="preserve">
|
||||
<value>Folder deleted.</value>
|
||||
@@ -276,7 +276,7 @@
|
||||
<value>আপনি লগ আউট করতে চান?</value>
|
||||
</data>
|
||||
<data name="RemoveAccount" xml:space="preserve">
|
||||
<value>Remove account</value>
|
||||
<value>অ্যাকাউন্ট অপসারণ করুন</value>
|
||||
</data>
|
||||
<data name="RemoveAccountConfirmation" xml:space="preserve">
|
||||
<value>Are you sure you want to remove this account?</value>
|
||||
@@ -315,30 +315,30 @@
|
||||
<comment>Label for notes.</comment>
|
||||
</data>
|
||||
<data name="Ok" xml:space="preserve">
|
||||
<value>Ok</value>
|
||||
<value>ঠিক আছে</value>
|
||||
<comment>Acknowledgement.</comment>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
<value>পাসওয়ার্ড</value>
|
||||
<comment>Label for a password.</comment>
|
||||
</data>
|
||||
<data name="Save" xml:space="preserve">
|
||||
<value>Save</value>
|
||||
<value>সংরক্ষণ করুন</value>
|
||||
<comment>Button text for a save operation (verb).</comment>
|
||||
</data>
|
||||
<data name="Move" xml:space="preserve">
|
||||
<value>Move</value>
|
||||
<value>স্থানান্তর করুন</value>
|
||||
</data>
|
||||
<data name="Saving" xml:space="preserve">
|
||||
<value>Saving...</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Settings</value>
|
||||
<value>সেটিংস</value>
|
||||
<comment>The title for the settings page.</comment>
|
||||
</data>
|
||||
<data name="Show" xml:space="preserve">
|
||||
<value>Show</value>
|
||||
<value>দেখান</value>
|
||||
<comment>Reveal a hidden value (password).</comment>
|
||||
</data>
|
||||
<data name="ItemDeleted" xml:space="preserve">
|
||||
@@ -346,17 +346,17 @@
|
||||
<comment>Confirmation message after successfully deleting a login.</comment>
|
||||
</data>
|
||||
<data name="Submit" xml:space="preserve">
|
||||
<value>Submit</value>
|
||||
<value>জমা দিন</value>
|
||||
</data>
|
||||
<data name="Sync" xml:space="preserve">
|
||||
<value>Sync</value>
|
||||
<comment>The title for the sync page.</comment>
|
||||
</data>
|
||||
<data name="ThankYou" xml:space="preserve">
|
||||
<value>Thank you</value>
|
||||
<value>ধন্যবাদ</value>
|
||||
</data>
|
||||
<data name="Tools" xml:space="preserve">
|
||||
<value>Tools</value>
|
||||
<value>টুলস</value>
|
||||
<comment>The title for the tools page.</comment>
|
||||
</data>
|
||||
<data name="URI" xml:space="preserve">
|
||||
@@ -379,7 +379,7 @@
|
||||
<comment>Confirmation message after successfully copying a value to the clipboard.</comment>
|
||||
</data>
|
||||
<data name="VerifyFingerprint" xml:space="preserve">
|
||||
<value>Verify fingerprint</value>
|
||||
<value>আঙ্গুলের ছাপ যাচাই করুন</value>
|
||||
</data>
|
||||
<data name="VerifyMasterPassword" xml:space="preserve">
|
||||
<value>প্রধান পাসওয়ার্ড যাচাইকরণ</value>
|
||||
@@ -388,32 +388,32 @@
|
||||
<value>Verify PIN</value>
|
||||
</data>
|
||||
<data name="Version" xml:space="preserve">
|
||||
<value>Version</value>
|
||||
<value>সংস্করণ</value>
|
||||
</data>
|
||||
<data name="View" xml:space="preserve">
|
||||
<value>View</value>
|
||||
</data>
|
||||
<data name="VisitOurWebsite" xml:space="preserve">
|
||||
<value>Visit our website</value>
|
||||
<value>আমাদের ওয়েবসাইটে ঢু মেরে আসুন</value>
|
||||
</data>
|
||||
<data name="VisitOurWebsiteDescription" xml:space="preserve">
|
||||
<value>Visit our website to get help, news, email us, and/or learn more about how to use Bitwarden.</value>
|
||||
<value>সাহায্য পেতে, খবর পেতে, আমাদের ইমেল করতে এবং/অথবা বিটওয়ার্ডেন কীভাবে ব্যবহার করবেন সে সম্পর্কে আরও জানতে আমাদের ওয়েবসাইট দেখুন।</value>
|
||||
</data>
|
||||
<data name="Website" xml:space="preserve">
|
||||
<value>Website</value>
|
||||
<value>ওয়েবসাইট</value>
|
||||
<comment>Label for a website.</comment>
|
||||
</data>
|
||||
<data name="Yes" xml:space="preserve">
|
||||
<value>Yes</value>
|
||||
<value>হ্যাঁ</value>
|
||||
</data>
|
||||
<data name="Account" xml:space="preserve">
|
||||
<value>Account</value>
|
||||
<value>অ্যাকাউন্ট</value>
|
||||
</data>
|
||||
<data name="AccountCreated" xml:space="preserve">
|
||||
<value>Your new account has been created! You may now log in.</value>
|
||||
<value>আপনার নতুন অ্যাকাউন্ট তৈরি করা হয়েছে! আপনি এখন লগইন করতে পারবেন।</value>
|
||||
</data>
|
||||
<data name="AddAnItem" xml:space="preserve">
|
||||
<value>Add an Item</value>
|
||||
<value>একটি আইটেম যোগ করুন</value>
|
||||
</data>
|
||||
<data name="AppExtension" xml:space="preserve">
|
||||
<value>App extension</value>
|
||||
@@ -425,7 +425,7 @@
|
||||
<value>Auto-fill service</value>
|
||||
</data>
|
||||
<data name="AvoidAmbiguousCharacters" xml:space="preserve">
|
||||
<value>Avoid ambiguous characters</value>
|
||||
<value>অস্পষ্ট বর্ণগুলি বাদ দিয়ে যান</value>
|
||||
</data>
|
||||
<data name="BitwardenAppExtension" xml:space="preserve">
|
||||
<value>Bitwarden app extension</value>
|
||||
@@ -440,13 +440,13 @@
|
||||
<value>Bitwarden Auto-fill Service</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillAccessibilityServiceDescription" xml:space="preserve">
|
||||
<value>Use the Bitwarden accessibility service to auto-fill your logins.</value>
|
||||
<value>আপনার লগইনগুলি স্বয়ংক্রিয়ভাবে পূরণ করতে বিটওয়ার্ডেন অ্যাক্সেসিবিলিটি পরিষেবা ব্যবহার করুন৷</value>
|
||||
</data>
|
||||
<data name="ChangeEmail" xml:space="preserve">
|
||||
<value>Change email</value>
|
||||
<value>ইমেইল পরিবর্তন করুন</value>
|
||||
</data>
|
||||
<data name="ChangeEmailConfirmation" xml:space="preserve">
|
||||
<value>You can change your email address on the bitwarden.com web vault. Do you want to visit the website now?</value>
|
||||
<value>আপনি bitwarden.com ওয়েব ভল্টে আপনার ইমেল ঠিকানা পরিবর্তন করতে পারেন। আপনি কি এখনই ওয়েবসাইট ভিজিট করতে চান?</value>
|
||||
</data>
|
||||
<data name="ChangeMasterPassword" xml:space="preserve">
|
||||
<value>প্রধান পাসওয়ার্ড পরিবর্তন</value>
|
||||
@@ -455,7 +455,7 @@
|
||||
<value>আপনি bitwarden.com ওয়েব ভল্ট থেকে প্রধান পাসওয়ার্ডটি পরিবর্তন করতে পারেন। আপনি কি এখনই ওয়েবসাইটটি দেখতে চান?</value>
|
||||
</data>
|
||||
<data name="Close" xml:space="preserve">
|
||||
<value>Close</value>
|
||||
<value>বন্ধ করুন</value>
|
||||
</data>
|
||||
<data name="Continue" xml:space="preserve">
|
||||
<value>অবিরত</value>
|
||||
@@ -480,7 +480,7 @@
|
||||
<value>Reactivate app extension</value>
|
||||
</data>
|
||||
<data name="ExtensionAlmostDone" xml:space="preserve">
|
||||
<value>Almost done!</value>
|
||||
<value>প্রায় হয়ে গেছে!</value>
|
||||
</data>
|
||||
<data name="ExtensionEnable" xml:space="preserve">
|
||||
<value>Activate app extension</value>
|
||||
@@ -493,7 +493,7 @@
|
||||
<value>Get instant access to your passwords!</value>
|
||||
</data>
|
||||
<data name="ExtensionReady" xml:space="preserve">
|
||||
<value>You're ready to log in!</value>
|
||||
<value>আপনি লগইন করার জন্য একদম তৈরি!</value>
|
||||
</data>
|
||||
<data name="ExtensionSetup" xml:space="preserve">
|
||||
<value>Your logins are now easily accessible from Safari, Chrome, and other supported apps.</value>
|
||||
@@ -511,7 +511,7 @@
|
||||
<value>প্রিয়</value>
|
||||
</data>
|
||||
<data name="Fingerprint" xml:space="preserve">
|
||||
<value>Fingerprint</value>
|
||||
<value>আঙুলের ছাপ</value>
|
||||
</data>
|
||||
<data name="GeneratePassword" xml:space="preserve">
|
||||
<value>পাসওয়ার্ড তৈরি করুন</value>
|
||||
@@ -584,7 +584,7 @@
|
||||
<value>যদি আপনি আপনার পাসওয়ার্ড ভুলে যান তাহলে একটি প্রধান পাসওয়ার্ডের ইঙ্গিতটি আপনাকে মনে করাতে সাহায্য করতে পারে।</value>
|
||||
</data>
|
||||
<data name="MasterPasswordLengthValMessageX" xml:space="preserve">
|
||||
<value>Master password must be at least {0} characters long.</value>
|
||||
<value>মাস্টার পাসওয়ার্ড কমপক্ষে {0} অক্ষরের হতে হবে।</value>
|
||||
</data>
|
||||
<data name="MinNumbers" xml:space="preserve">
|
||||
<value>সর্বনিম্ন সংখ্যা</value>
|
||||
@@ -595,7 +595,7 @@
|
||||
<comment>Minimum special characters for password generator settings</comment>
|
||||
</data>
|
||||
<data name="MoreSettings" xml:space="preserve">
|
||||
<value>More settings</value>
|
||||
<value>আরও সেটিংস</value>
|
||||
</data>
|
||||
<data name="MustLogInMainApp" xml:space="preserve">
|
||||
<value>You must log into the main Bitwarden app before you can use the extension.</value>
|
||||
@@ -651,7 +651,7 @@
|
||||
<comment>Push notifications for apple products</comment>
|
||||
</data>
|
||||
<data name="RateTheApp" xml:space="preserve">
|
||||
<value>Rate the app</value>
|
||||
<value>অ্যাপ্লিকেশনটকে রেট দিন</value>
|
||||
</data>
|
||||
<data name="RateTheAppDescription" xml:space="preserve">
|
||||
<value>দয়া করে একটি ভাল পর্যালোচনার মাধ্যমে সাহায্য করতে আমাদের বিবেচনা করুন!</value>
|
||||
@@ -684,7 +684,7 @@
|
||||
<value>Item saved</value>
|
||||
</data>
|
||||
<data name="Submitting" xml:space="preserve">
|
||||
<value>Submitting...</value>
|
||||
<value>জমা দেওয়া হচ্ছে...</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="Syncing" xml:space="preserve">
|
||||
@@ -701,7 +701,7 @@
|
||||
<value>Sync vault now</value>
|
||||
</data>
|
||||
<data name="TouchID" xml:space="preserve">
|
||||
<value>Touch ID</value>
|
||||
<value>টাচ আইডি</value>
|
||||
<comment>What Apple calls their fingerprint reader.</comment>
|
||||
</data>
|
||||
<data name="TwoStepLogin" xml:space="preserve">
|
||||
@@ -717,17 +717,17 @@
|
||||
<value>Unlock with PIN code</value>
|
||||
</data>
|
||||
<data name="Validating" xml:space="preserve">
|
||||
<value>Validating</value>
|
||||
<value>কার্যকর করা হচ্ছে</value>
|
||||
<comment>Message shown when interacting with the server</comment>
|
||||
</data>
|
||||
<data name="VerificationCode" xml:space="preserve">
|
||||
<value>Verification code</value>
|
||||
<value>যাচাইকরণ কোড</value>
|
||||
</data>
|
||||
<data name="ViewItem" xml:space="preserve">
|
||||
<value>View item</value>
|
||||
</data>
|
||||
<data name="WebVault" xml:space="preserve">
|
||||
<value>Bitwarden web vault</value>
|
||||
<value>বিটওয়ার্ডেন ওয়েব ভল্ট</value>
|
||||
</data>
|
||||
<data name="Lost2FAApp" xml:space="preserve">
|
||||
<value>Lost authenticator app?</value>
|
||||
@@ -740,10 +740,10 @@
|
||||
<value>Extension activated!</value>
|
||||
</data>
|
||||
<data name="Icons" xml:space="preserve">
|
||||
<value>Icons</value>
|
||||
<value>আইকন</value>
|
||||
</data>
|
||||
<data name="Translations" xml:space="preserve">
|
||||
<value>Translations</value>
|
||||
<value>অনুবাদসমূহ</value>
|
||||
</data>
|
||||
<data name="ItemsForUri" xml:space="preserve">
|
||||
<value>Items for {0}</value>
|
||||
@@ -769,19 +769,19 @@
|
||||
<value>2. Switch on the toggle and press OK to accept.</value>
|
||||
</data>
|
||||
<data name="Disabled" xml:space="preserve">
|
||||
<value>Disabled</value>
|
||||
<value>নিষ্ক্রিয়</value>
|
||||
</data>
|
||||
<data name="Enabled" xml:space="preserve">
|
||||
<value>Enabled</value>
|
||||
<value>সক্রিয়</value>
|
||||
</data>
|
||||
<data name="Off" xml:space="preserve">
|
||||
<value>Off</value>
|
||||
<value>বন্ধ</value>
|
||||
</data>
|
||||
<data name="On" xml:space="preserve">
|
||||
<value>On</value>
|
||||
<value>চালু</value>
|
||||
</data>
|
||||
<data name="Status" xml:space="preserve">
|
||||
<value>Status</value>
|
||||
<value>অবস্থা</value>
|
||||
</data>
|
||||
<data name="BitwardenAutofillServiceAlert2" xml:space="preserve">
|
||||
<value>The easiest way to add new logins to your vault is from the Bitwarden Auto-fill Service. Learn more about using the Bitwarden Auto-fill Service by navigating to the "Settings" screen.</value>
|
||||
@@ -876,7 +876,7 @@
|
||||
<value>Unable to download file.</value>
|
||||
</data>
|
||||
<data name="UnableToOpenFile" xml:space="preserve">
|
||||
<value>Your device cannot open this type of file.</value>
|
||||
<value>আপনার ডিভাইস এই ধরনের ফাইল খুলতে পারে না।</value>
|
||||
</data>
|
||||
<data name="Downloading" xml:space="preserve">
|
||||
<value>ডাউনলোড হচ্ছে...</value>
|
||||
@@ -904,13 +904,13 @@
|
||||
Scanning will happen automatically.</value>
|
||||
</data>
|
||||
<data name="ScanQrTitle" xml:space="preserve">
|
||||
<value>Scan QR Code</value>
|
||||
<value>QR কোড স্ক্যান করুন</value>
|
||||
</data>
|
||||
<data name="Camera" xml:space="preserve">
|
||||
<value>Camera</value>
|
||||
<value>ক্যামেরা</value>
|
||||
</data>
|
||||
<data name="Photos" xml:space="preserve">
|
||||
<value>Photos</value>
|
||||
<value>ছবিসমূহ</value>
|
||||
</data>
|
||||
<data name="CopyTotp" xml:space="preserve">
|
||||
<value>Copy TOTP</value>
|
||||
@@ -934,7 +934,7 @@ Scanning will happen automatically.</value>
|
||||
<value>Choose file</value>
|
||||
</data>
|
||||
<data name="File" xml:space="preserve">
|
||||
<value>File</value>
|
||||
<value>ফাইল</value>
|
||||
</data>
|
||||
<data name="NoFileChosen" xml:space="preserve">
|
||||
<value>No file chosen</value>
|
||||
@@ -1080,7 +1080,7 @@ Scanning will happen automatically.</value>
|
||||
<value>নামের শেষাংশ</value>
|
||||
</data>
|
||||
<data name="FullName" xml:space="preserve">
|
||||
<value>Full name</value>
|
||||
<value>পুরো নাম</value>
|
||||
</data>
|
||||
<data name="LicenseNumber" xml:space="preserve">
|
||||
<value>লাইসেন্স নম্বর</value>
|
||||
@@ -1107,34 +1107,34 @@ Scanning will happen automatically.</value>
|
||||
<value>Mx</value>
|
||||
</data>
|
||||
<data name="November" xml:space="preserve">
|
||||
<value>November</value>
|
||||
<value>নভেম্বর</value>
|
||||
</data>
|
||||
<data name="October" xml:space="preserve">
|
||||
<value>October</value>
|
||||
<value>অক্টোবর</value>
|
||||
</data>
|
||||
<data name="PassportNumber" xml:space="preserve">
|
||||
<value>Passport number</value>
|
||||
<value>পাসপোর্ট নম্বর</value>
|
||||
</data>
|
||||
<data name="Phone" xml:space="preserve">
|
||||
<value>Phone</value>
|
||||
<value>ফোন</value>
|
||||
</data>
|
||||
<data name="September" xml:space="preserve">
|
||||
<value>September</value>
|
||||
<value>সেপ্টেম্বর</value>
|
||||
</data>
|
||||
<data name="SSN" xml:space="preserve">
|
||||
<value>Social Security number</value>
|
||||
<value>সামাজিক সুরক্ষা নম্বর</value>
|
||||
</data>
|
||||
<data name="StateProvince" xml:space="preserve">
|
||||
<value>State / Province</value>
|
||||
<value>রাজ্য / প্রদেশ</value>
|
||||
</data>
|
||||
<data name="Title" xml:space="preserve">
|
||||
<value>Title</value>
|
||||
<value>শিরোনাম</value>
|
||||
</data>
|
||||
<data name="ZipPostalCode" xml:space="preserve">
|
||||
<value>Zip / Postal code</value>
|
||||
<value>জিপ / পোস্টকোড</value>
|
||||
</data>
|
||||
<data name="Address" xml:space="preserve">
|
||||
<value>Address</value>
|
||||
<value>ঠিকানা</value>
|
||||
</data>
|
||||
<data name="Expiration" xml:space="preserve">
|
||||
<value>Expiration</value>
|
||||
@@ -1204,7 +1204,7 @@ Scanning will happen automatically.</value>
|
||||
<value>Custom field name</value>
|
||||
</data>
|
||||
<data name="FieldTypeBoolean" xml:space="preserve">
|
||||
<value>Boolean</value>
|
||||
<value>বুলিয়ান</value>
|
||||
</data>
|
||||
<data name="FieldTypeHidden" xml:space="preserve">
|
||||
<value>Hidden</value>
|
||||
@@ -1225,7 +1225,7 @@ Scanning will happen automatically.</value>
|
||||
<value>Remove</value>
|
||||
</data>
|
||||
<data name="NewUri" xml:space="preserve">
|
||||
<value>New URI</value>
|
||||
<value>নতুন URI</value>
|
||||
</data>
|
||||
<data name="URIPosition" xml:space="preserve">
|
||||
<value>URI {0}</value>
|
||||
@@ -1272,7 +1272,7 @@ Scanning will happen automatically.</value>
|
||||
<value>Hold your Yubikey near the top of the device.</value>
|
||||
</data>
|
||||
<data name="TryAgain" xml:space="preserve">
|
||||
<value>Try again</value>
|
||||
<value>আবার চেষ্টা করুন</value>
|
||||
</data>
|
||||
<data name="YubiKeyInstructionIos" xml:space="preserve">
|
||||
<value>To continue, hold your YubiKey NEO against the back of the device.</value>
|
||||
@@ -1440,16 +1440,16 @@ Scanning will happen automatically.</value>
|
||||
<value>Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved.</value>
|
||||
</data>
|
||||
<data name="NumberOfWords" xml:space="preserve">
|
||||
<value>Number of words</value>
|
||||
<value>শব্দসংখ্যা</value>
|
||||
</data>
|
||||
<data name="Passphrase" xml:space="preserve">
|
||||
<value>Passphrase</value>
|
||||
<value>গুপ্ত-বাক্যাংশ</value>
|
||||
</data>
|
||||
<data name="WordSeparator" xml:space="preserve">
|
||||
<value>Word separator</value>
|
||||
<value>শব্দ বিভাজক</value>
|
||||
</data>
|
||||
<data name="Clear" xml:space="preserve">
|
||||
<value>Clear</value>
|
||||
<value>পরিষ্কার করুন</value>
|
||||
<comment>To clear something out. example: To clear browser history.</comment>
|
||||
</data>
|
||||
<data name="Generator" xml:space="preserve">
|
||||
@@ -1474,42 +1474,42 @@ Scanning will happen automatically.</value>
|
||||
<value>Export vault</value>
|
||||
</data>
|
||||
<data name="LockNow" xml:space="preserve">
|
||||
<value>Lock now</value>
|
||||
<value>এখনই লক করুন</value>
|
||||
</data>
|
||||
<data name="PIN" xml:space="preserve">
|
||||
<value>PIN</value>
|
||||
<value>পিন</value>
|
||||
</data>
|
||||
<data name="Unlock" xml:space="preserve">
|
||||
<value>Unlock</value>
|
||||
<value>আনলক করুন</value>
|
||||
</data>
|
||||
<data name="UnlockVault" xml:space="preserve">
|
||||
<value>Unlock vault</value>
|
||||
</data>
|
||||
<data name="ThirtyMinutes" xml:space="preserve">
|
||||
<value>30 minutes</value>
|
||||
<value>৩০ মিনিট</value>
|
||||
</data>
|
||||
<data name="SetPINDescription" xml:space="preserve">
|
||||
<value>Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application.</value>
|
||||
<value>Bitwarden আনলক করার জন্য আপনার পিন কোডটি সেট করুন। আপনি যদি অ্যাপ্লিকেশনটি থেকে পুরোপুরি লগ আউট করেন তবে আপনার পিন সেটিংস রিসেট করা হবে।</value>
|
||||
</data>
|
||||
<data name="LoggedInAsOn" xml:space="preserve">
|
||||
<value>Logged in as {0} on {1}.</value>
|
||||
<value>{1}-এ {0} হিসেবে লগইন করা হয়েছে।</value>
|
||||
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
|
||||
</data>
|
||||
<data name="VaultLockedMasterPassword" xml:space="preserve">
|
||||
<value>আপনার ভল্ট লক করা আছে। চালিয়ে যেতে আপনার প্রধান পাসওয়ার্ডটি যাচাই করান।</value>
|
||||
</data>
|
||||
<data name="VaultLockedPIN" xml:space="preserve">
|
||||
<value>Your vault is locked. Verify your PIN code to continue.</value>
|
||||
<value>আপনার ভল্ট লক করা আছে। চালিয়ে যেতে আপনার পিন কোড যাচাই করান।</value>
|
||||
</data>
|
||||
<data name="VaultLockedIdentity" xml:space="preserve">
|
||||
<value>Your vault is locked. Verify your identity to continue.</value>
|
||||
<value>আপনার ভল্ট লক করা আছে। চালিয়ে যেতে আপনার পরিচয় যাচাই করান।</value>
|
||||
</data>
|
||||
<data name="Dark" xml:space="preserve">
|
||||
<value>Dark</value>
|
||||
<value>গাঢ়</value>
|
||||
<comment>A dark color</comment>
|
||||
</data>
|
||||
<data name="Light" xml:space="preserve">
|
||||
<value>Light</value>
|
||||
<value>উজ্জ্বল</value>
|
||||
<comment>A light color</comment>
|
||||
</data>
|
||||
<data name="FiveMinutes" xml:space="preserve">
|
||||
@@ -1752,11 +1752,11 @@ Scanning will happen automatically.</value>
|
||||
<value>Do you really want to send to the trash?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometric unlock disabled pending verification of master password.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometric unlock for this account is disabled pending verification of master password.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Biometric unlock for autofill disabled pending verification of master password.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Autofill biometric unlock for this account is disabled pending verification of master password.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Allow sync on refresh</value>
|
||||
@@ -1887,10 +1887,10 @@ Scanning will happen automatically.</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="Text" xml:space="preserve">
|
||||
<value>Text</value>
|
||||
<value>লেখা</value>
|
||||
</data>
|
||||
<data name="TypeText" xml:space="preserve">
|
||||
<value>Text</value>
|
||||
<value>লেখা</value>
|
||||
</data>
|
||||
<data name="TypeTextInfo" xml:space="preserve">
|
||||
<value>The text you want to send.</value>
|
||||
@@ -1900,7 +1900,7 @@ Scanning will happen automatically.</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="TypeFile" xml:space="preserve">
|
||||
<value>File</value>
|
||||
<value>ফাইল</value>
|
||||
</data>
|
||||
<data name="TypeFileInfo" xml:space="preserve">
|
||||
<value>The file you want to send.</value>
|
||||
@@ -1918,7 +1918,7 @@ Scanning will happen automatically.</value>
|
||||
<value>Text type is not selected, tap to select.</value>
|
||||
</data>
|
||||
<data name="DeletionDate" xml:space="preserve">
|
||||
<value>Deletion date</value>
|
||||
<value>মুছে ফেলার তারিখ</value>
|
||||
</data>
|
||||
<data name="DeletionTime" xml:space="preserve">
|
||||
<value>Deletion time</value>
|
||||
@@ -1957,7 +1957,7 @@ Scanning will happen automatically.</value>
|
||||
<value>Current access count</value>
|
||||
</data>
|
||||
<data name="NewPassword" xml:space="preserve">
|
||||
<value>New password</value>
|
||||
<value>নতুন পাসওয়ার্ড</value>
|
||||
</data>
|
||||
<data name="PasswordInfo" xml:space="preserve">
|
||||
<value>Optionally require a password for users to access this Send.</value>
|
||||
@@ -2030,19 +2030,19 @@ Scanning will happen automatically.</value>
|
||||
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
|
||||
</data>
|
||||
<data name="OneDay" xml:space="preserve">
|
||||
<value>1 day</value>
|
||||
<value>১ দিন</value>
|
||||
</data>
|
||||
<data name="TwoDays" xml:space="preserve">
|
||||
<value>2 days</value>
|
||||
<value>২ দিন</value>
|
||||
</data>
|
||||
<data name="ThreeDays" xml:space="preserve">
|
||||
<value>3 days</value>
|
||||
</data>
|
||||
<data name="SevenDays" xml:space="preserve">
|
||||
<value>7 days</value>
|
||||
<value>৭ দিন</value>
|
||||
</data>
|
||||
<data name="ThirtyDays" xml:space="preserve">
|
||||
<value>30 days</value>
|
||||
<value>৩০ দিন</value>
|
||||
</data>
|
||||
<data name="Custom" xml:space="preserve">
|
||||
<value>Custom</value>
|
||||
@@ -2141,7 +2141,13 @@ Scanning will happen automatically.</value>
|
||||
<value>This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s)</value>
|
||||
<value>Your organization policies have set your maximum allowed vault timeout to {0} hour(s) and {1} minute(s).</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organization policies have set your vault timeout action to {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Your vault timeout exceeds the restrictions set by your organization.</value>
|
||||
@@ -2234,16 +2240,16 @@ Scanning will happen automatically.</value>
|
||||
<value>Options are collapsed, tap to expand.</value>
|
||||
</data>
|
||||
<data name="UppercaseAtoZ" xml:space="preserve">
|
||||
<value>Uppercase (A to Z)</value>
|
||||
<value>বড় হাতের অক্ষর (A-Z)</value>
|
||||
</data>
|
||||
<data name="LowercaseAtoZ" xml:space="preserve">
|
||||
<value>Lowercase (A to Z)</value>
|
||||
</data>
|
||||
<data name="NumbersZeroToNine" xml:space="preserve">
|
||||
<value>Numbers (0 to 9)</value>
|
||||
<value>সংখ্যা (0-9)</value>
|
||||
</data>
|
||||
<data name="SpecialCharacters" xml:space="preserve">
|
||||
<value>Special characters (!@#$%^&*)</value>
|
||||
<value>বিশেষ অক্ষর (!@#$%^&*)</value>
|
||||
</data>
|
||||
<data name="TapToGoBack" xml:space="preserve">
|
||||
<value>Tap to go back</value>
|
||||
@@ -2346,10 +2352,10 @@ select Add TOTP to store the key safely</value>
|
||||
<value>Deny login</value>
|
||||
</data>
|
||||
<data name="JustNow" xml:space="preserve">
|
||||
<value>Just now</value>
|
||||
<value>এইমাত্র</value>
|
||||
</data>
|
||||
<data name="XMinutesAgo" xml:space="preserve">
|
||||
<value>{0} minutes ago</value>
|
||||
<value>{0} মিনিট আগে</value>
|
||||
</data>
|
||||
<data name="LogInAccepted" xml:space="preserve">
|
||||
<value>Login confirmed</value>
|
||||
@@ -2490,8 +2496,8 @@ Do you want to switch to this account?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Get master password hint</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Logging in as {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Logging in as {0} on {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Not you?</value>
|
||||
@@ -2542,7 +2548,7 @@ Do you want to switch to this account?</value>
|
||||
<value>Enable camera permission to use the scanner</value>
|
||||
</data>
|
||||
<data name="Language" xml:space="preserve">
|
||||
<value>Language</value>
|
||||
<value>ভাষা</value>
|
||||
</data>
|
||||
<data name="LanguageChangeXDescription" xml:space="preserve">
|
||||
<value>The language has been changed to {0}. Please restart the app to see the change</value>
|
||||
@@ -2569,10 +2575,10 @@ Do you want to switch to this account?</value>
|
||||
<value>Weak</value>
|
||||
</data>
|
||||
<data name="Good" xml:space="preserve">
|
||||
<value>Good</value>
|
||||
<value>ভালো</value>
|
||||
</data>
|
||||
<data name="Strong" xml:space="preserve">
|
||||
<value>Strong</value>
|
||||
<value>শক্তিশালী</value>
|
||||
</data>
|
||||
<data name="CheckKnownDataBreachesForThisPassword" xml:space="preserve">
|
||||
<value>Check known data breaches for this password</value>
|
||||
@@ -2604,4 +2610,37 @@ Do you want to switch to this account?</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>There are no items that match the search</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>US</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>EU</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Self-hosted</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Data region</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Current master password</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Master password re-prompt help</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Invalid API key</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Invalid API token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<value>Želite li zaista poslati u smeće?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometrijsko otključavanje onemogućeno do potvrde glavne lozinke.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometric unlock for this account is disabled pending verification of master password.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Biometrijsko otključavanje za auto-ispunu onemogućeno do potvrde glavne lozinke.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Autofill biometric unlock for this account is disabled pending verification of master password.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Uključi sinkronizaciju pri osvježavanju</value>
|
||||
@@ -2142,6 +2142,12 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Pravilo tvoje organizacije utječe na vrijeme isteka trezora. Najveće dozvoljeno vrijeme isteka je {0} sata(i) i {1} minuta.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organization policies have set your vault timeout action to {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Vrijeme isteka premašuje ograničenje koju je postavila tvoja organizacija.</value>
|
||||
</data>
|
||||
@@ -2488,8 +2494,8 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Dobijte podsjetnik glavne lozinke</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Prijava kao {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Logging in as {0} on {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Nisi ti?</value>
|
||||
@@ -2602,4 +2608,37 @@ Skeniranje će biti izvršeno automatski.</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>There are no items that match the search</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>US</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>EU</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Self-hosted</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Data region</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Current master password</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Master password re-prompt help</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Invalid API key</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Invalid API token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@ L'escaneig es farà automàticament.</value>
|
||||
<value>Esteu segur que voleu enviar-ho a la paperera?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>S'ha detectat un canvi biomètric. Inicieu la sessió mitjançant la contrasenya principal per tornar a activar-la.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>El desbloqueig biomètric d'aquest compte està deshabilitat mentre es verifica la contrasenya mestra.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Desbloqueig biomètric d'emplenament automàtic deshabilitat. Està pendent de verificació de la contrasenya mestra.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>El desbloqueig biomètric d'emplenament automàtic d'aquest compte està deshabilitat mentre es verifica la contrasenya mestra.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Activa la sincronització en actualitzar-se</value>
|
||||
@@ -2142,6 +2142,12 @@ L'escaneig es farà automàticament.</value>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Les polítiques de l'organització afecten el temps d'espera de la caixa forta. El temps d'espera màxim permès de la caixa forta és de {0} hores i {1} minuts</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Les polítiques de l'organització afecten el temps d'espera de la vostra caixa forta. El temps d'espera màxim permès és de {0} hores i {1} minuts. L'acció de temps d'espera de la caixa forta està definida en {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Les polítiques de l'organització han establert l'acció de temps d'espera de la caixa forta a {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>El temps d'espera de la caixa forta supera les restriccions establertes per la vostra organització.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@ Voleu canviar a aquest compte?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Obteniu la pista de la contrasenya mestra</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Connectat com {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Inici de sessió com a {0} a {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>No sou vosaltres?</value>
|
||||
@@ -2603,4 +2609,37 @@ Voleu canviar a aquest compte?</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>No hi ha elements que coincidisquen amb la cerca</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>EUA</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>UE</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Autoallotjat</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Regió de dades</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Regió</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>La vostra contrasenya mestra no compleix una o més de les polítiques de l'organització. Per accedir a la caixa forta, heu d'actualitzar-la ara. Si continueu, es tancarà la sessió actual i us demanarà que torneu a iniciar-la. Les sessions en altres dispositius poden continuar romanent actives fins a una hora.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Contrasenya mestra actual</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Ajuda per tornar a demanar la contrasenya mestra</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>El desbloqueig pot fallar a causa de memòria insuficient. Disminueix la configuració de memòria KDF per resoldre-ho</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Clau API no vàlida</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Token API no vàlid</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2646
src/App/Resources/AppResources.cy.resx
Normal file
2646
src/App/Resources/AppResources.cy.resx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1752,11 +1752,11 @@ Skanning vil ske automatisk.</value>
|
||||
<value>Er du sikker på, at du sende til papirkurven?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometrisk oplåsning deaktiveret - afventer verifikation af hovedadgangskoden.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometrisk oplåsning af denne konto deaktiveret afventende bekræftelse af hovedadgangskode.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Biometrisk oplåsning til autoudfyldning deaktiveret - afventer verifikation af hovedadgangskoden.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Autoudfyldelse for biometrisk oplåsning af denne konto deaktiveret afventende bekræftelse af hovedadgangskode.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Tillad synk ved opfriskning</value>
|
||||
@@ -2142,6 +2142,12 @@ Skanning vil ske automatisk.</value>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Dine organisationspolitikker påvirker din boks-timeout. Maksimum tilladte boks-timeout er {0} time(r) og {1} minut(ter)</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Organisationspolitikkerne påvirker boks-timeout. Maks. tilladt boks-timeout er {0} time(r) og {1} minut(ter). Boks-timeout er pt. sat til {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Organisationspolitikker har sat boks-timeouthandlingen til {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Timeout for din boks overskrider de begrænsninger, der er angivet af din organisation.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@ Vil du skifte til denne konto?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Få hovedadgangskodetip</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Logger ind som {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Logger ind som {0} på {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Ikke dig?</value>
|
||||
@@ -2603,4 +2609,37 @@ Vil du skifte til denne konto?</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>Ingen emner matcher søgningen</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>USA</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>EU</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Selv-hostet</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Dataregion</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Din hovedadgangskode overholder ikke én eller flere organisationspolitikker. For at få adgang til boksen skal hovedadgangskode opdateres nu. Fortsættes, logges du ud af den nuværende session og vil skulle logger ind igen. Aktive sessioner på andre enheder kan forblive aktive i op til én time.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Aktuel hovedadgangskode</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Hjælp til genanmodning om hovedadgangskode</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Oplåsning kan fejle grundet utilstrækkelig hukommelse. Reducér KDF-hukommelsesindstillinger for at afhjælpe</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Ugyldig API-nøgle</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Ugyldigt API-token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@ Das Scannen erfolgt automatisch.</value>
|
||||
<value>Soll dieser Eintrag wirklich in den Papierkorb verschoben werden?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometrisches Entsperren ist deaktiviert, bis das Master-Passwort eingegeben wurde.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Das Entsperren über Biometrie ist für dieses Konto deaktiviert, bis das Master-Passwort verifiziert wurde.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Biometrisches Entsperren für automatisches Ausfüllen ist deaktiviert, bis das Master-Passwort eingegeben wurde.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Das Entsperren von Auto-Ausfüllen über Biometrie ist für dieses Konto deaktiviert, bis das Master-Passwort verifiziert wurde.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Synchronisation beim Aktualisieren aktivieren</value>
|
||||
@@ -2140,7 +2140,13 @@ Das Scannen erfolgt automatisch.</value>
|
||||
<value>Diese Organisation hat eine Unternehmensrichtlinie, die dich automatisch für die Passwortzurücksetzung registriert. Die Registrierung wird es Administratoren der Organisation erlauben, dein Master-Passwort zu ändern.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Deine Organisationsrichtlinien haben Auswirkungen auf dein Tresor-Timeout. Das maximal zulässige Tresor-Timeout beträgt {0} Stunde(n) und {1} Minute(n)</value>
|
||||
<value>Deine Unternehmensrichtlinien haben das maximal zulässige Tresor-Timeout auf {0} Stunde(n) und {1} Minute(n) festgelegt.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Deine Organisationsrichtlinien beeinflussen dein Tresor-Timeout. Das maximal zulässige Tresor-Timeout beträgt {0} Stunde(n) und {1} Minute(n). Deine Tresor-Timeout-Aktion ist auf {2} gesetzt.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Deine Organisationsrichtlinien haben deine Tresor-Timeout-Aktion auf {0} gesetzt.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Dein Tresor-Timeout überschreitet die von deinem Unternehmen festgelegten Beschränkungen.</value>
|
||||
@@ -2488,8 +2494,8 @@ Möchtest du zu diesem Konto wechseln?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Hinweis zum Master-Passwort erhalten</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Anmelden als {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Anmelden als {0} auf {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Nicht du?</value>
|
||||
@@ -2602,4 +2608,37 @@ Möchtest du zu diesem Konto wechseln?</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>Es gibt keine Einträge, die mit der Suche übereinstimmen</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>US</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>EU</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Selbst gehostet</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Datenregion</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Dein Master-Passwort entspricht nicht einer oder mehreren Richtlinien deiner Organisation. Um auf den Tresor zugreifen zu können, musst du dein Master-Passwort jetzt aktualisieren. Wenn du fortfährst, wirst du von deiner aktuellen Sitzung abgemeldet und musst dich erneut anmelden. Aktive Sitzungen auf anderen Geräten können noch bis zu einer Stunde lang aktiv bleiben.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Aktuelles Master-Passwort</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Hilfe zum erneuten Abfragen des Master-Passworts</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Das Entsperren kann aufgrund von unzureichendem Arbeitsspeicher fehlschlagen. Verringere deine KDF-Speichereinstellungen, um das Problem zu beheben.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Ungültiger API-Schlüssel</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Ungültiger API-Token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@
|
||||
<value>Θέλετε πραγματικά να στείλετε στον κάδο απορριμμάτων;</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Εντοπίστηκε βιομετρική αλλαγή, συνδεθείτε χρησιμοποιώντας τον κύριο κωδικό πρόσβασης για ενεργοποίηση ξανά.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Το βιομετρικό ξεκλείδωμα για αυτόν τον λογαριασμό είναι απενεργοποιημένο εν αναμονή της επαλήθευσης του κύριου κωδικού πρόσβασης.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Το βιομετρικό ξεκλείδωμα για αυτόματη συμπλήρωση απενεργοποιήθηκε εν αναμονή της επαλήθευσης του κύριου κωδικού πρόσβασης.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Το βιομετρικό ξεκλείδωμα αυτόματης συμπλήρωσης για αυτό το λογαριασμό είναι απενεργοποιημένο εν αναμονή της επαλήθευσης του κύριου κωδικού πρόσβασης.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Ενεργοποίηση συγχρονισμού κατά την ανανέωση</value>
|
||||
@@ -2142,6 +2142,12 @@
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Οι πολιτικές του οργανισμού σας επηρεάζουν το χρονικό όριο vault σας. Το μέγιστο επιτρεπόμενο Χρονικό όριο Vault είναι {0} ώρα(ες) και {1} λεπτό(ά)</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Οι πολιτικές του οργανισμού σας επηρεάζουν το χρονικό όριο του vault σας. Το μέγιστο επιτρεπόμενο χρονικό όριο vault είναι {0} ώρα(ες) και {1} λεπτό(ά). Το χρονικό όριο του vault σας έχει οριστεί σε {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Οι πολιτικές του οργανισμού σας έχουν ορίσει την ενέργεια χρονικού ορίου vault σε {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Το χρονικό όριο του vault σας υπερβαίνει τους περιορισμούς που έχει ορίσει ο οργανισμός σας.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Λάβετε υπόδειξη κύριου κωδικού</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Σύνδεση ως {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Σύνδεση ως {0} στις {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Δεν είστε εσείς;</value>
|
||||
@@ -2603,4 +2609,37 @@
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>Δεν υπάρχουν στοιχεία που να ταιριάζουν με την αναζήτηση</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>ΗΠΑ</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>ΕΕ</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Αυτο-φιλοξενούμενο</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Περιοχή δεδομένων</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Περιοχή</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Ο κύριος κωδικός πρόσβασής σας δεν πληροί μία ή περισσότερες πολιτικές του οργανισμού σας. Για να αποκτήσετε πρόσβαση στο Vault σας, πρέπει να ενημερώσετε τον κύριο κωδικό πρόσβασής σας τώρα. Η διαδικασία θα σας αποσυνδέσει από την τρέχουσα συνεδρία σας, απαιτώντας από εσάς να συνδεθείτε ξανά. Οι ενεργές συνεδρίες σε άλλες συσκευές ενδέχεται να συνεχίσουν να είναι ενεργές εώς και μία ώρα.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Τρέχων κύριος κωδικός</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Master password re-prompt help</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Invalid API key</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Invalid API token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -1752,11 +1752,11 @@ Scanning will happen automatically.</value>
|
||||
<value>Do you really want to send to the bin?</value>
|
||||
<comment>Confirmation alert message when soft-deleting a cipher.</comment>
|
||||
</data>
|
||||
<data name="BiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometric unlock disabled pending verification of master password.</value>
|
||||
<data name="AccountBiometricInvalidated" xml:space="preserve">
|
||||
<value>Biometric unlock for this account is disabled pending verification of master password.</value>
|
||||
</data>
|
||||
<data name="BiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Biometric unlock for autofill disabled pending verification of master password.</value>
|
||||
<data name="AccountBiometricInvalidatedExtension" xml:space="preserve">
|
||||
<value>Autofill biometric unlock for this account is disabled pending verification of master password.</value>
|
||||
</data>
|
||||
<data name="EnableSyncOnRefresh" xml:space="preserve">
|
||||
<value>Allow sync on refresh</value>
|
||||
@@ -2142,6 +2142,12 @@ Scanning will happen automatically.</value>
|
||||
<data name="VaultTimeoutPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organisation policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s)</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutPolicyWithActionInEffect" xml:space="preserve">
|
||||
<value>Your organization policies are affecting your vault timeout. Maximum allowed vault timeout is {0} hour(s) and {1} minute(s). Your vault timeout action is set to {2}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutActionPolicyInEffect" xml:space="preserve">
|
||||
<value>Your organization policies have set your vault timeout action to {0}.</value>
|
||||
</data>
|
||||
<data name="VaultTimeoutToLarge" xml:space="preserve">
|
||||
<value>Your vault timeout exceeds the restrictions set by your organisation.</value>
|
||||
</data>
|
||||
@@ -2489,8 +2495,8 @@ Do you want to switch to this account?</value>
|
||||
<data name="GetMasterPasswordwordHint" xml:space="preserve">
|
||||
<value>Get master password hint</value>
|
||||
</data>
|
||||
<data name="LoggingInAsX" xml:space="preserve">
|
||||
<value>Logging in as {0}</value>
|
||||
<data name="LoggingInAsXOnY" xml:space="preserve">
|
||||
<value>Logging in as {0} on {1}</value>
|
||||
</data>
|
||||
<data name="NotYou" xml:space="preserve">
|
||||
<value>Not you?</value>
|
||||
@@ -2603,4 +2609,37 @@ Do you want to switch to this account?</value>
|
||||
<data name="ThereAreNoItemsThatMatchTheSearch" xml:space="preserve">
|
||||
<value>There are no items that match the search</value>
|
||||
</data>
|
||||
<data name="US" xml:space="preserve">
|
||||
<value>US</value>
|
||||
</data>
|
||||
<data name="EU" xml:space="preserve">
|
||||
<value>EU</value>
|
||||
</data>
|
||||
<data name="SelfHosted" xml:space="preserve">
|
||||
<value>Self-hosted</value>
|
||||
</data>
|
||||
<data name="DataRegion" xml:space="preserve">
|
||||
<value>Data region</value>
|
||||
</data>
|
||||
<data name="Region" xml:space="preserve">
|
||||
<value>Region</value>
|
||||
</data>
|
||||
<data name="UpdateWeakMasterPasswordWarning" xml:space="preserve">
|
||||
<value>Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour.</value>
|
||||
</data>
|
||||
<data name="CurrentMasterPassword" xml:space="preserve">
|
||||
<value>Current master password</value>
|
||||
</data>
|
||||
<data name="MasterPasswordRePromptHelp" xml:space="preserve">
|
||||
<value>Master password re-prompt help</value>
|
||||
</data>
|
||||
<data name="UnlockingMayFailDueToInsufficientMemoryDecreaseYourKDFMemorySettingsToResolve" xml:space="preserve">
|
||||
<value>Unlocking may fail due to insufficient memory. Decrease your KDF memory settings to resolve.</value>
|
||||
</data>
|
||||
<data name="InvalidAPIKey" xml:space="preserve">
|
||||
<value>Invalid API key</value>
|
||||
</data>
|
||||
<data name="InvalidAPIToken" xml:space="preserve">
|
||||
<value>Invalid API token</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user