mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
226 Commits
PM-2149-im
...
feature/ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f4bbafe3c | ||
|
|
a5804df6a3 | ||
|
|
bfa2a51608 | ||
|
|
32be08daae | ||
|
|
0a628cc8a8 | ||
|
|
80c424ed03 | ||
|
|
99fb5463cf | ||
|
|
c5d941e1df | ||
|
|
3edfef6169 | ||
|
|
1c8742511a | ||
|
|
8e424d6c05 | ||
|
|
390c303b90 | ||
|
|
443f7282b8 | ||
|
|
50109ee70b | ||
|
|
9ffdfd51cc | ||
|
|
04e409f3c6 | ||
|
|
6c143bad57 | ||
|
|
286e18059a | ||
|
|
553bf9ed0a | ||
|
|
ddb27b52d3 | ||
|
|
6c504aa710 | ||
|
|
62254aef8d | ||
|
|
06a0195a6d | ||
|
|
df2b0b21d5 | ||
|
|
e6b1bab860 | ||
|
|
ce41eb0578 | ||
|
|
1a0b52d644 | ||
|
|
16ada4993c | ||
|
|
3795f3aa17 | ||
|
|
eceb506c77 | ||
|
|
f013f69669 | ||
|
|
f98dfa6581 | ||
|
|
0723999652 | ||
|
|
2c7870d660 | ||
|
|
f02b3415a3 | ||
|
|
beda4e9ff8 | ||
|
|
df4d89cd52 | ||
|
|
5f12bb9747 | ||
|
|
5712639492 | ||
|
|
e0a3c301fb | ||
|
|
27306fe353 | ||
|
|
a31f15559f | ||
|
|
0e75f3f5c8 | ||
|
|
363da063fa | ||
|
|
974a571455 | ||
|
|
96343eccf7 | ||
|
|
e0c721098c | ||
|
|
a86f6e3034 | ||
|
|
fe17288b99 | ||
|
|
7324da9d47 | ||
|
|
793c5fef6f | ||
|
|
3a13ba4efa | ||
|
|
69aa6fc044 | ||
|
|
c5288d3921 | ||
|
|
9506595fdd | ||
|
|
7a65bf7fd7 | ||
|
|
d0ce89fedb | ||
|
|
3c94ea4579 | ||
|
|
e840dc2e30 | ||
|
|
eb25ee5d1b | ||
|
|
840f24dbe5 | ||
|
|
c6309173ba | ||
|
|
946c465f0c | ||
|
|
658c1eaf64 | ||
|
|
02b0265767 | ||
|
|
bd2481b3e4 | ||
|
|
e90409d842 | ||
|
|
484b5a5160 | ||
|
|
12c72b2833 | ||
|
|
2688209752 | ||
|
|
53e0e55915 | ||
|
|
ca57948d9f | ||
|
|
2e5fb414b5 | ||
|
|
aaf082faba | ||
|
|
e7aeb08cae | ||
|
|
f177968958 | ||
|
|
f1d59210f9 | ||
|
|
4dda7a6634 | ||
|
|
62213c0aaf | ||
|
|
a1808f64b3 | ||
|
|
8be8abb8fe | ||
|
|
142c3145f0 | ||
|
|
174acbc558 | ||
|
|
4bcc7c0d71 | ||
|
|
14b2960f30 | ||
|
|
455c3a257c | ||
|
|
72de17bd1d | ||
|
|
8c623a2067 | ||
|
|
3cdf1c2f0e | ||
|
|
ce9503fa0c | ||
|
|
ed3467515e | ||
|
|
2e4da1b87d | ||
|
|
21fc56457d | ||
|
|
bc2eb212a6 | ||
|
|
a1912526c2 | ||
|
|
9d0209751c | ||
|
|
f2936c95fa | ||
|
|
bb2f1f0f5f | ||
|
|
5a0c2115a1 | ||
|
|
a67f50b145 | ||
|
|
d63a219272 | ||
|
|
c92cd90a97 | ||
|
|
1dcd3a3daa | ||
|
|
757e5ea647 | ||
|
|
efb8763d3c | ||
|
|
90649d1c8b | ||
|
|
b23f29511c | ||
|
|
71731bb9b7 | ||
|
|
f2be840a7d | ||
|
|
828055791f | ||
|
|
685e0f407a | ||
|
|
87eebda55f | ||
|
|
7542d1ae1c | ||
|
|
990de4ea4e | ||
|
|
0dbc23f734 | ||
|
|
9f6c8601d3 | ||
|
|
8b7f9b9fb3 | ||
|
|
d17789d5ee | ||
|
|
b8f0747dd4 | ||
|
|
8ef9443b1e | ||
|
|
bbef0f8c93 | ||
|
|
3cdf5ccd3b | ||
|
|
e97a37222a | ||
|
|
218a30b510 | ||
|
|
828043ec97 | ||
|
|
b25c8b0842 | ||
|
|
a4a0d31fc6 | ||
|
|
6ef6cf5d84 | ||
|
|
597f629920 | ||
|
|
b8cef16711 | ||
|
|
c4f6ae9077 | ||
|
|
8b9658d2c5 | ||
|
|
43bf0fbdb3 | ||
|
|
11922c6f49 | ||
|
|
a6f05338c2 | ||
|
|
b932824b5a | ||
|
|
efd1671f48 | ||
|
|
3e2005e5ed | ||
|
|
382eee2ed3 | ||
|
|
b0f1dd00ee | ||
|
|
5961a001ab | ||
|
|
9026dd10e5 | ||
|
|
355261679d | ||
|
|
7f14ec9b5d | ||
|
|
0c72626916 | ||
|
|
f21fae7fea | ||
|
|
6d4792bc24 | ||
|
|
dbadf8c56f | ||
|
|
4d0f9d1c03 | ||
|
|
68759fc608 | ||
|
|
47be3d6aef | ||
|
|
7ec5c8ccfd | ||
|
|
819aabb330 | ||
|
|
9c7ff853d7 | ||
|
|
e30f9903d1 | ||
|
|
249406e3a8 | ||
|
|
8cae840c68 | ||
|
|
e274c04107 | ||
|
|
7043be67dd | ||
|
|
afb8c515d6 | ||
|
|
bfcfd367dd | ||
|
|
a23454bc53 | ||
|
|
6f7100ae4f | ||
|
|
01ac20e6e4 | ||
|
|
8474f536ff | ||
|
|
f426c0e370 | ||
|
|
420dc09fd1 | ||
|
|
6d4793d592 | ||
|
|
eea7c6b7d7 | ||
|
|
ec93a61275 | ||
|
|
c34d1da6e6 | ||
|
|
c4e64e082b | ||
|
|
5aaff1ea20 | ||
|
|
0271a4db4c | ||
|
|
375718f945 | ||
|
|
9eda015371 | ||
|
|
ea81acb3bf | ||
|
|
174549e5bc | ||
|
|
87b1d18872 | ||
|
|
ae9ba810ff | ||
|
|
dd52ff0dcc | ||
|
|
c678c17ebc | ||
|
|
cd9e49b13b | ||
|
|
6d7970f767 | ||
|
|
9adc4d3080 | ||
|
|
1f20f70d13 | ||
|
|
a25da68437 | ||
|
|
fdc0313d10 | ||
|
|
f31c87b52e | ||
|
|
1e79e1182f | ||
|
|
11947ce99a | ||
|
|
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 |
34
.github/CODEOWNERS
vendored
Normal file
34
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Please sort lines alphabetically, this will ensure we don't accidentally add duplicates.
|
||||||
|
#
|
||||||
|
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
|
||||||
|
|
||||||
|
# The following owners will be the default owners for everything in the repo.
|
||||||
|
# Unless a later match takes precedence
|
||||||
|
# @bitwarden/tech-leads
|
||||||
|
|
||||||
|
@bitwarden/dept-development-mobile
|
||||||
|
|
||||||
|
## Auth team files ##
|
||||||
|
|
||||||
|
## Platform team files ##
|
||||||
|
appIcons @bitwarden/team-platform-dev
|
||||||
|
build.cake @bitwarden/team-platform-dev
|
||||||
|
|
||||||
|
## Vault team files ##
|
||||||
|
src/watchOS @bitwarden/team-vault-dev
|
||||||
|
|
||||||
|
## Tools team files ##
|
||||||
|
src/Core/Services/EmailForwarders @bitwarden/team-tools-dev
|
||||||
|
|
||||||
|
## Crowdin Sync files ##
|
||||||
|
src/App/Resources @bitwarden/team-tools-dev
|
||||||
|
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/team-tools-dev
|
||||||
|
store/apple @bitwarden/team-tools-dev
|
||||||
|
store/google @bitwarden/team-tools-dev
|
||||||
|
|
||||||
|
## Locales ##
|
||||||
|
src/App/Resources/AppResources.Designer.cs
|
||||||
|
src/App/Resources/AppResources.resx
|
||||||
|
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj
|
||||||
|
store/apple/en
|
||||||
|
store/google/en
|
||||||
57
.github/renovate.json
vendored
57
.github/renovate.json
vendored
@@ -1,22 +1,37 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": [
|
||||||
"config:base",
|
"config:base",
|
||||||
"schedule:monthly",
|
":combinePatchMinorReleases",
|
||||||
":maintainLockFilesMonthly",
|
":dependencyDashboard",
|
||||||
":preserveSemverRanges",
|
":maintainLockFilesWeekly",
|
||||||
":rebaseStalePrs",
|
":pinAllExceptPeerDependencies",
|
||||||
":disableDependencyDashboard"
|
":prConcurrentLimit10",
|
||||||
],
|
":rebaseStalePrs",
|
||||||
"enabledManagers": [
|
"schedule:weekends",
|
||||||
"nuget"
|
":separateMajorReleases"
|
||||||
],
|
],
|
||||||
"packageRules": [
|
"enabledManagers": ["cargo", "github-actions", "npm", "nuget"],
|
||||||
{
|
"packageRules": [
|
||||||
"matchManagers": ["nuget"],
|
{
|
||||||
"groupName": "Nuget updates",
|
"groupName": "cargo minor",
|
||||||
"groupSlug": "nuget",
|
"matchManagers": ["cargo"],
|
||||||
"separateMajorMinor": false
|
"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"]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
525
.github/workflows/build.yml
vendored
525
.github/workflows/build.yml
vendored
@@ -11,21 +11,26 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs: {}
|
inputs: {}
|
||||||
|
|
||||||
|
env:
|
||||||
|
main_app_folder_path: src/App
|
||||||
|
main_app_project_path: src/App/App.csproj
|
||||||
|
target-net-version: net8.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cloc:
|
# cloc:
|
||||||
name: CLOC
|
# name: CLOC
|
||||||
runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
steps:
|
# steps:
|
||||||
- name: Checkout repo
|
# - name: Checkout repo
|
||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
# uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||||
|
|
||||||
- name: Set up CLOC
|
# - name: Set up CLOC
|
||||||
run: |
|
# run: |
|
||||||
sudo apt-get update
|
# sudo apt-get update
|
||||||
sudo apt-get -y install cloc
|
# sudo apt-get -y install cloc
|
||||||
|
|
||||||
- name: Print lines of code
|
# - name: Print lines of code
|
||||||
run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML
|
# run: cloc --vcs git --exclude-dir Resources,store,test,Properties --include-lang C#,XAML
|
||||||
|
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
@@ -56,7 +61,6 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
|
||||||
android:
|
android:
|
||||||
name: Android
|
name: Android
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
@@ -65,37 +69,30 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
variant: ["prod", "qa"]
|
variant: ["prod", "qa"]
|
||||||
|
env:
|
||||||
|
android_folder_path: src/App/Platforms/Android
|
||||||
steps:
|
steps:
|
||||||
- name: Setup NuGet
|
- name: Setup NuGet
|
||||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||||
with:
|
with:
|
||||||
nuget-version: 5.9.0
|
nuget-version: 6.4.0
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
- name: Set up MSBuild
|
- name: Set up MSBuild
|
||||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
|
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
|
||||||
|
|
||||||
|
# This step might be obsolete at some point as .NET MAUI workloads
|
||||||
|
# are starting to come pre-installed on the GH Actions build agents.
|
||||||
|
- name: Install MAUI Workload
|
||||||
|
run: dotnet workload install maui --ignore-failed-sources
|
||||||
|
|
||||||
- name: Setup Windows builder
|
- name: Setup Windows builder
|
||||||
run: choco install checksum --no-progress
|
run: choco install checksum --no-progress
|
||||||
|
|
||||||
- name: Work Around for broken Windows 2022 Runner Image
|
|
||||||
run: |
|
|
||||||
Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
|
|
||||||
$InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
|
|
||||||
$componentsToAdd = @(
|
|
||||||
"Component.Xamarin"
|
|
||||||
)
|
|
||||||
[string]$workloadArgs = $componentsToAdd | ForEach-Object {" --add " + $_}
|
|
||||||
$Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache')
|
|
||||||
$process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden
|
|
||||||
if ($process.ExitCode -eq 0)
|
|
||||||
{
|
|
||||||
Write-Host "components have been successfully added"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write-Host "components were not installed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
nuget help | grep Version
|
nuget help | grep Version
|
||||||
@@ -115,9 +112,9 @@ jobs:
|
|||||||
mkdir -p ~/secrets
|
mkdir -p ~/secrets
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
||||||
--output ./src/Android/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg
|
--output ./${{ env.main_app_folder_path }}/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
||||||
--output ./src/Android/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg
|
--output ./${{ env.main_app_folder_path }}/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
||||||
--output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg
|
--output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -127,7 +124,7 @@ jobs:
|
|||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
||||||
--output ./src/Android/google-services.json ./.github/secrets/google-services.json.gpg
|
--output ./${{ env.android_folder_path }}/google-services.json ./.github/secrets/google-services.json.gpg
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Increment version
|
- name: Increment version
|
||||||
run: |
|
run: |
|
||||||
@@ -138,7 +135,7 @@ jobs:
|
|||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
|
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
|
||||||
./src/Android/Properties/AndroidManifest.xml
|
./${{ env.android_folder_path }}/AndroidManifest.xml
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Restore packages
|
- name: Restore packages
|
||||||
@@ -148,22 +145,22 @@ jobs:
|
|||||||
run: dotnet tool restore
|
run: dotnet tool restore
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Verify Format
|
# - name: Verify Format
|
||||||
run: dotnet tool run dotnet-format --check
|
# run: dotnet tool run dotnet-format --check
|
||||||
shell: pwsh
|
# shell: pwsh
|
||||||
|
|
||||||
- name: Run Core tests
|
#- name: Run Core tests
|
||||||
run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx"
|
# run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx"
|
||||||
shell: pwsh
|
# shell: pwsh
|
||||||
|
|
||||||
- name: Report test results
|
#- name: Report test results
|
||||||
uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
|
# uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
|
||||||
if: always()
|
# if: always()
|
||||||
with:
|
# with:
|
||||||
name: Test Results
|
# name: Test Results
|
||||||
path: "**/test-results.trx"
|
# path: "**/test-results.trx"
|
||||||
reporter: dotnet-trx
|
# reporter: dotnet-trx
|
||||||
fail-on-error: true
|
# fail-on-error: true
|
||||||
|
|
||||||
- name: Build Play Store publisher
|
- name: Build Play Store publisher
|
||||||
if: ${{ matrix.variant == 'prod' }}
|
if: ${{ matrix.variant == 'prod' }}
|
||||||
@@ -175,12 +172,13 @@ jobs:
|
|||||||
- name: Build Android
|
- name: Build Android
|
||||||
run: |
|
run: |
|
||||||
$configuration = "Release";
|
$configuration = "Release";
|
||||||
|
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Build $configuration Configuration"
|
Write-Output "##### Build $configuration Configuration"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
|
|
||||||
|
|
||||||
|
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Sign Android Build
|
- name: Sign Android Build
|
||||||
@@ -188,7 +186,7 @@ jobs:
|
|||||||
PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }}
|
PLAY_KEYSTORE_PASSWORD: ${{ secrets.PLAY_KEYSTORE_PASSWORD }}
|
||||||
UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }}
|
UPLOAD_KEYSTORE_PASSWORD: ${{ secrets.UPLOAD_KEYSTORE_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
|
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
|
||||||
$packageName = "com.x8bit.bitwarden";
|
$packageName = "com.x8bit.bitwarden";
|
||||||
|
|
||||||
if ("${{ matrix.variant }}" -ne "prod")
|
if ("${{ matrix.variant }}" -ne "prod")
|
||||||
@@ -199,16 +197,13 @@ jobs:
|
|||||||
Write-Output "##### Sign Google Play Bundle Release Configuration"
|
Write-Output "##### Sign Google Play Bundle Release Configuration"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidPackageFormats=aab /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_upload-keystore.jks") /p:AndroidSigningKeyAlias=upload /p:AndroidSigningKeyPass="$($env:UPLOAD_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:UPLOAD_KEYSTORE_PASSWORD)" --no-restore
|
||||||
"/p:AndroidSigningKeyAlias=upload" "/p:AndroidSigningKeyPass=$($env:UPLOAD_KEYSTORE_PASSWORD)" `
|
|
||||||
"/p:AndroidSigningKeyStore=$("app_upload-keystore.jks")" `
|
|
||||||
"/p:AndroidSigningStorePass=$($env:UPLOAD_KEYSTORE_PASSWORD)" "/p:AndroidPackageFormat=aab" "/v:quiet"
|
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Copy Google Play Bundle to project root"
|
Write-Output "##### Copy Google Play Bundle to project root"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
$signedAabPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/Release/$($packageName)-Signed.aab");
|
$signedAabPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.aab");
|
||||||
$signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab");
|
$signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab");
|
||||||
Copy-Item $signedAabPath $signedAabDestPath
|
Copy-Item $signedAabPath $signedAabDestPath
|
||||||
|
|
||||||
@@ -216,16 +211,13 @@ jobs:
|
|||||||
Write-Output "##### Sign APK Release Configuration"
|
Write-Output "##### Sign APK Release Configuration"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_play-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:PLAY_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:PLAY_KEYSTORE_PASSWORD)" --no-restore
|
||||||
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:PLAY_KEYSTORE_PASSWORD)" `
|
|
||||||
"/p:AndroidSigningKeyStore=$("app_play-keystore.jks")" `
|
|
||||||
"/p:AndroidSigningStorePass=$($env:PLAY_KEYSTORE_PASSWORD)" "/v:quiet"
|
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Copy Release APK to project root"
|
Write-Output "##### Copy Release APK to project root"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
$signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/Release/$($packageName)-Signed.apk");
|
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk");
|
||||||
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).apk");
|
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).apk");
|
||||||
|
|
||||||
Copy-Item $signedApkPath $signedApkDestPath
|
Copy-Item $signedApkPath $signedApkDestPath
|
||||||
@@ -301,38 +293,31 @@ jobs:
|
|||||||
f-droid:
|
f-droid:
|
||||||
name: F-Droid Build
|
name: F-Droid Build
|
||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
|
env:
|
||||||
|
android_folder_path: src/App/Platforms/Android
|
||||||
|
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml
|
||||||
steps:
|
steps:
|
||||||
- name: Setup NuGet
|
- name: Setup NuGet
|
||||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||||
with:
|
with:
|
||||||
nuget-version: 5.9.0
|
nuget-version: 6.4.0
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
- name: Set up MSBuild
|
- name: Set up MSBuild
|
||||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
|
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # v1.3.1
|
||||||
|
|
||||||
|
# This step might be obsolete at some point as .NET MAUI workloads
|
||||||
|
# are starting to come pre-installed on the GH Actions build agents.
|
||||||
|
- name: Install MAUI Workload
|
||||||
|
run: dotnet workload install maui --ignore-failed-sources
|
||||||
|
|
||||||
- name: Setup Windows builder
|
- name: Setup Windows builder
|
||||||
run: choco install checksum --no-progress
|
run: choco install checksum --no-progress
|
||||||
|
|
||||||
- name: Work Around for broken Windows 2022 Runner Image
|
|
||||||
run: |
|
|
||||||
Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
|
|
||||||
$InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise"
|
|
||||||
$componentsToAdd = @(
|
|
||||||
"Component.Xamarin"
|
|
||||||
)
|
|
||||||
[string]$workloadArgs = $componentsToAdd | ForEach-Object {" --add " + $_}
|
|
||||||
$Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache')
|
|
||||||
$process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden
|
|
||||||
if ($process.ExitCode -eq 0)
|
|
||||||
{
|
|
||||||
Write-Host "components have been successfully added"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Write-Host "components were not installed"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
nuget help | grep Version
|
nuget help | grep Version
|
||||||
@@ -351,7 +336,7 @@ jobs:
|
|||||||
mkdir -p ~/secrets
|
mkdir -p ~/secrets
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
||||||
--output ./src/Android/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg
|
--output ./${{ env.main_app_folder_path }}/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Increment version
|
- name: Increment version
|
||||||
@@ -363,30 +348,28 @@ jobs:
|
|||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
|
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
|
||||||
./src/Android/Properties/AndroidManifest.xml
|
./${{ env.android_manifest_path }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Clean for F-Droid
|
- name: Clean for F-Droid
|
||||||
run: |
|
run: |
|
||||||
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
|
$appPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
|
||||||
$appPath = $($env:GITHUB_WORKSPACE + "/src/App/App.csproj");
|
|
||||||
$corePath = $($env:GITHUB_WORKSPACE + "/src/Core/Core.csproj");
|
$corePath = $($env:GITHUB_WORKSPACE + "/src/Core/Core.csproj");
|
||||||
|
|
||||||
$androidManifest = $($env:GITHUB_WORKSPACE + "/src/Android/Properties/AndroidManifest.xml");
|
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}");
|
||||||
|
|
||||||
Write-Output "########################################"
|
# Write-Output "########################################"
|
||||||
Write-Output "##### Clean Android and App"
|
# Write-Output "##### Clean Android and App"
|
||||||
Write-Output "########################################"
|
# Write-Output "########################################"
|
||||||
|
|
||||||
msbuild "$($androidPath)" "/t:Clean" "/p:Configuration=FDroid"
|
# msbuild "$($androidPath)" "/t:Clean" "/p:Configuration=FDroid"
|
||||||
msbuild "$($appPath)" "/t:Clean" "/p:Configuration=FDroid"
|
# msbuild "$($appPath)" "/t:Clean" "/p:Configuration=FDroid"
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Backup project files"
|
Write-Output "##### Backup project files"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
Copy-Item $androidManifest $($androidManifest + ".original");
|
Copy-Item $androidManifest $($androidManifest + ".original");
|
||||||
Copy-Item $androidPath $($androidPath + ".original");
|
|
||||||
Copy-Item $appPath $($appPath + ".original");
|
Copy-Item $appPath $($appPath + ".original");
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
@@ -401,76 +384,77 @@ jobs:
|
|||||||
|
|
||||||
$xml.Save($androidManifest);
|
$xml.Save($androidManifest);
|
||||||
|
|
||||||
Write-Output "########################################"
|
# Write-Output "########################################"
|
||||||
Write-Output "##### Uninstall from Android.csproj"
|
# Write-Output "##### Uninstall from App.csproj"
|
||||||
Write-Output "########################################"
|
# Write-Output "########################################"
|
||||||
|
|
||||||
$xml=New-Object XML;
|
# $xml=New-Object XML;
|
||||||
$xml.Load($androidPath);
|
# $xml.Load($appPath);
|
||||||
|
|
||||||
$ns=New-Object System.Xml.XmlNamespaceManager($xml.NameTable);
|
# $ns=New-Object System.Xml.XmlNamespaceManager($xml.NameTable);
|
||||||
$ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI);
|
# $ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI);
|
||||||
|
|
||||||
$firebaseNode=$xml.SelectSingleNode(`
|
# $firebaseNode=$xml.SelectSingleNode(`
|
||||||
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Firebase.Messaging']", $ns);
|
# "/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Firebase.Messaging']", $ns);
|
||||||
$firebaseNode.ParentNode.RemoveChild($firebaseNode);
|
# $firebaseNode.ParentNode.RemoveChild($firebaseNode);
|
||||||
|
|
||||||
$daggerNode=$xml.SelectSingleNode(`
|
# $daggerNode=$xml.SelectSingleNode(`
|
||||||
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Google.Dagger']", $ns);
|
# "/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Google.Dagger']", $ns);
|
||||||
$daggerNode.ParentNode.RemoveChild($daggerNode);
|
# $daggerNode.ParentNode.RemoveChild($daggerNode);
|
||||||
|
|
||||||
$safetyNetNode=$xml.SelectSingleNode(`
|
# $safetyNetNode=$xml.SelectSingleNode(`
|
||||||
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.GooglePlayServices.SafetyNet']", $ns);
|
# "/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.GooglePlayServices.SafetyNet']", $ns);
|
||||||
$safetyNetNode.ParentNode.RemoveChild($safetyNetNode);
|
# $safetyNetNode.ParentNode.RemoveChild($safetyNetNode);
|
||||||
|
|
||||||
$xml.Save($androidPath);
|
# $xml.Save($appPath);
|
||||||
|
|
||||||
Write-Output "########################################"
|
# Write-Output "########################################"
|
||||||
Write-Output "##### Uninstall from Core.csproj"
|
# Write-Output "##### Uninstall from Core.csproj"
|
||||||
Write-Output "########################################"
|
# Write-Output "########################################"
|
||||||
|
|
||||||
$xml=New-Object XML;
|
# $xml=New-Object XML;
|
||||||
$xml.Load($corePath);
|
# $xml.Load($corePath);
|
||||||
|
|
||||||
$appCenterNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='Microsoft.AppCenter.Crashes']");
|
# $appCenterNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='Microsoft.AppCenter.Crashes']");
|
||||||
$appCenterNode.ParentNode.RemoveChild($appCenterNode);
|
# $appCenterNode.ParentNode.RemoveChild($appCenterNode);
|
||||||
|
|
||||||
$xml.Save($corePath);
|
# $xml.Save($corePath);
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Restore packages
|
- name: Restore packages
|
||||||
run: nuget restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build for F-Droid
|
- name: Build for F-Droid
|
||||||
run: |
|
run: |
|
||||||
$configuration = "FDroid";
|
$configuration = "Release";
|
||||||
|
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Build $configuration Configuration"
|
Write-Output "##### Build $configuration FDROID
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
|
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android /p:CustomConstants="FDROID"
|
||||||
|
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
- name: Sign for F-Droid
|
- name: Sign for F-Droid
|
||||||
env:
|
env:
|
||||||
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
|
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
|
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
|
||||||
|
$packageName = "com.x8bit.bitwarden";
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Sign FDroid Configuration"
|
Write-Output "##### Sign FDroid"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" `
|
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android /p:AndroidKeyStore=true /p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks") /p:AndroidSigningKeyAlias=bitwarden /p:AndroidSigningKeyPass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:AndroidSigningStorePass="$($env:FDROID_KEYSTORE_PASSWORD)" /p:CustomConstants="FDROID" --no-restore
|
||||||
"/t:SignAndroidPackage" "/p:Configuration=FDroid" "/p:AndroidKeyStore=true" `
|
|
||||||
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:FDROID_KEYSTORE_PASSWORD)" `
|
|
||||||
"/p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks")" `
|
|
||||||
"/p:AndroidSigningStorePass=$($env:FDROID_KEYSTORE_PASSWORD)" "/v:quiet"
|
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Copy FDroid apk to project root"
|
Write-Output "##### Copy FDroid apk to project root"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
|
|
||||||
$signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/FDroid/com.x8bit.bitwarden-Signed.apk");
|
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk");
|
||||||
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/com.x8bit.bitwarden-fdroid.apk");
|
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/com.x8bit.bitwarden-fdroid.apk");
|
||||||
|
|
||||||
Copy-Item $signedApkPath $signedApkDestPath
|
Copy-Item $signedApkPath $signedApkDestPath
|
||||||
@@ -495,21 +479,40 @@ jobs:
|
|||||||
path: ./bw-fdroid-apk-sha256.txt
|
path: ./bw-fdroid-apk-sha256.txt
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
# Disabling iOS build from this branch until fixing publish/build
|
||||||
|
# really long time
|
||||||
ios:
|
ios:
|
||||||
name: Apple iOS
|
name: Apple iOS
|
||||||
runs-on: macos-12
|
if: github.ref == 'refs/heads/master'
|
||||||
|
runs-on: macos-13
|
||||||
needs: setup
|
needs: setup
|
||||||
|
env:
|
||||||
|
ios_folder_path: src/App/Platforms/iOS
|
||||||
|
app_output_name: App
|
||||||
steps:
|
steps:
|
||||||
|
- name: Set XCode version
|
||||||
|
uses: maxim-lobanov/setup-xcode@v1
|
||||||
|
with:
|
||||||
|
xcode-version: 15.0.1
|
||||||
|
|
||||||
- name: Setup NuGet
|
- name: Setup NuGet
|
||||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||||
with:
|
with:
|
||||||
nuget-version: 5.9.0
|
nuget-version: 6.4.0
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
# This step might be obsolete at some point as .NET MAUI workloads
|
||||||
|
# are starting to come pre-installed on the GH Actions build agents.
|
||||||
|
- name: Install MAUI Workload
|
||||||
|
run: dotnet workload install maui --ignore-failed-sources
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
run: |
|
run: |
|
||||||
nuget help | grep Version
|
nuget help | grep Version
|
||||||
msbuild -version
|
|
||||||
dotnet --info
|
dotnet --info
|
||||||
echo "GitHub ref: $GITHUB_REF"
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
@@ -520,7 +523,7 @@ jobs:
|
|||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
|
||||||
with:
|
with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
@@ -575,7 +578,7 @@ jobs:
|
|||||||
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
|
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS/Info.plist
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist
|
||||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
|
||||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Autofill/Info.plist
|
||||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.ShareExtension/Info.plist
|
||||||
@@ -590,7 +593,7 @@ jobs:
|
|||||||
echo "##### Updating Entitlements"
|
echo "##### Updating Entitlements"
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
|
|
||||||
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./src/iOS/Entitlements.plist
|
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>production<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Set up Keychain
|
- name: Set up Keychain
|
||||||
@@ -641,6 +644,9 @@ jobs:
|
|||||||
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
cp $WATCH_APP_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_EXTENSION_UUID.mobileprovision"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
- name: Restore packages
|
||||||
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Bulid WatchApp
|
- name: Bulid WatchApp
|
||||||
run: |
|
run: |
|
||||||
echo "########################################"
|
echo "########################################"
|
||||||
@@ -654,19 +660,26 @@ jobs:
|
|||||||
echo "########################################"
|
echo "########################################"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Restore packages
|
|
||||||
run: nuget restore
|
|
||||||
|
|
||||||
- name: Archive Build for App Store
|
- name: Archive Build for App Store
|
||||||
run: |
|
run: |
|
||||||
$configuration = "AppStore";
|
Write-Output "########################################"
|
||||||
$platform = "iPhone";
|
Write-Output "##### Archive for Release ios-arm64
|
||||||
|
Write-Output "########################################"
|
||||||
|
|
||||||
|
dotnet publish ${{ env.main_app_project_path }} -c Release -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=ios-arm64 /p:ArchiveOnBuild=true
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Archive $configuration Configuration for $platform Platform"
|
Write-Output "##### Done"
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
msbuild "$($env:GITHUB_WORKSPACE + "/src/iOS/iOS.csproj")" "/p:Platform=$platform" `
|
shell: pwsh
|
||||||
"/p:Configuration=$configuration" "/p:ArchiveOnBuild=true" "/t:`"Build`""
|
|
||||||
|
- name: Archive Build for Mobile Automation
|
||||||
|
run: |
|
||||||
|
Write-Output "########################################"
|
||||||
|
Write-Output "##### Archive Releae for iossimulator-arm64
|
||||||
|
Write-Output "########################################"
|
||||||
|
|
||||||
|
dotnet publish ${{ env.main_app_project_path }} -c Release -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=iossimulator-arm64 /p:ArchiveOnBuild=true
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "########################################"
|
||||||
Write-Output "##### Done"
|
Write-Output "##### Done"
|
||||||
@@ -684,6 +697,15 @@ jobs:
|
|||||||
-exportOptionsPlist $EXPORT_OPTIONS_PATH
|
-exportOptionsPlist $EXPORT_OPTIONS_PATH
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
- name: Export .app for Automation CI
|
||||||
|
run: |
|
||||||
|
ARCHIVE_PATH="./${{ env.main_app_folder_path }}/bin/Release/iossimulator-arm64/publish/${{ env.app_output_name }}.app"
|
||||||
|
EXPORT_PATH="./bitwarden-export"
|
||||||
|
|
||||||
|
zip -r -q ${{ env.app_output_name }}.app.zip $ARCHIVE_PATH
|
||||||
|
mv ${{ env.app_output_name }}.app.zip $EXPORT_PATH
|
||||||
|
shell: bash
|
||||||
|
|
||||||
- name: Copy all dSYMs files to upload
|
- name: Copy all dSYMs files to upload
|
||||||
run: |
|
run: |
|
||||||
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
|
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
|
||||||
@@ -702,10 +724,17 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: Bitwarden iOS
|
name: Bitwarden iOS
|
||||||
path: |
|
path: |
|
||||||
./bitwarden-export/Bitwarden.ipa
|
./bitwarden-export/${{ env.app_output_name }}.ipa
|
||||||
./bitwarden-export/dSYMs/*.*
|
./bitwarden-export/dSYMs/*.*
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload .app file for Automation CI
|
||||||
|
uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0
|
||||||
|
with:
|
||||||
|
name: ${{ env.app_output_name }}.app.zip
|
||||||
|
path: ./bitwarden-export/${{ env.app_output_name }}.app.zip
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Install AppCenter CLI
|
- name: Install AppCenter CLI
|
||||||
if: |
|
if: |
|
||||||
(github.ref == 'refs/heads/master'
|
(github.ref == 'refs/heads/master'
|
||||||
@@ -754,116 +783,116 @@ jobs:
|
|||||||
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
||||||
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
xcrun altool --upload-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \
|
xcrun altool --upload-app --type ios --file "./bitwarden-export/${{ env.app_output_name }}.ipa" \
|
||||||
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
|
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
|
||||||
crowdin-push:
|
# crowdin-push:
|
||||||
name: Crowdin Push
|
# name: Crowdin Push
|
||||||
if: github.ref == 'refs/heads/master'
|
# if: github.ref == 'refs/heads/master'
|
||||||
needs:
|
# needs:
|
||||||
- android
|
# - android
|
||||||
- f-droid
|
# - f-droid
|
||||||
- ios
|
# - ios
|
||||||
runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
env:
|
# env:
|
||||||
_CROWDIN_PROJECT_ID: "269690"
|
# _CROWDIN_PROJECT_ID: "269690"
|
||||||
steps:
|
# steps:
|
||||||
- name: Checkout repo
|
# - name: Checkout repo
|
||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
# uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
# - name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
# uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
|
||||||
with:
|
# with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
# creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
# - name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
# id: retrieve-secrets
|
||||||
env:
|
# env:
|
||||||
KEYVAULT: bitwarden-ci
|
# KEYVAULT: bitwarden-ci
|
||||||
SECRETS: |
|
# SECRETS: |
|
||||||
crowdin-api-token
|
# crowdin-api-token
|
||||||
run: |
|
# run: |
|
||||||
for i in ${SECRETS//,/ }
|
# for i in ${SECRETS//,/ }
|
||||||
do
|
# do
|
||||||
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
|
# VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
|
||||||
echo "::add-mask::$VALUE"
|
# echo "::add-mask::$VALUE"
|
||||||
echo "$i=$VALUE" >> $GITHUB_OUTPUT
|
# echo "$i=$VALUE" >> $GITHUB_OUTPUT
|
||||||
done
|
# done
|
||||||
|
|
||||||
- name: Upload Sources
|
# - name: Upload Sources
|
||||||
uses: crowdin/github-action@ecd7eb0ef6f3cfa16293c79e9cbc4bc5b5fd9c49 # v1.4.9
|
# uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
|
||||||
env:
|
# env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
# CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||||
with:
|
# with:
|
||||||
config: crowdin.yml
|
# config: crowdin.yml
|
||||||
crowdin_branch_name: master
|
# crowdin_branch_name: master
|
||||||
upload_sources: true
|
# upload_sources: true
|
||||||
upload_translations: false
|
# upload_translations: false
|
||||||
|
|
||||||
|
|
||||||
check-failures:
|
# check-failures:
|
||||||
name: Check for failures
|
# name: Check for failures
|
||||||
if: always()
|
# if: always()
|
||||||
runs-on: ubuntu-20.04
|
# runs-on: ubuntu-20.04
|
||||||
needs:
|
# needs:
|
||||||
- cloc
|
# - cloc
|
||||||
- android
|
# - android
|
||||||
- f-droid
|
# - f-droid
|
||||||
- ios
|
# - ios
|
||||||
- crowdin-push
|
# - crowdin-push
|
||||||
steps:
|
# steps:
|
||||||
- name: Check if any job failed
|
# - name: Check if any job failed
|
||||||
if: |
|
# if: |
|
||||||
(github.ref == 'refs/heads/master')
|
# (github.ref == 'refs/heads/master')
|
||||||
|| (github.ref == 'refs/heads/rc')
|
# || (github.ref == 'refs/heads/rc')
|
||||||
|| (github.ref == 'refs/heads/hotfix-rc')
|
# || (github.ref == 'refs/heads/hotfix-rc')
|
||||||
env:
|
# env:
|
||||||
CLOC_STATUS: ${{ needs.cloc.result }}
|
# CLOC_STATUS: ${{ needs.cloc.result }}
|
||||||
ANDROID_STATUS: ${{ needs.android.result }}
|
# ANDROID_STATUS: ${{ needs.android.result }}
|
||||||
F_DROID_STATUS: ${{ needs.f-droid.result }}
|
# F_DROID_STATUS: ${{ needs.f-droid.result }}
|
||||||
IOS_STATUS: ${{ needs.ios.result }}
|
# IOS_STATUS: ${{ needs.ios.result }}
|
||||||
CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }}
|
# CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }}
|
||||||
run: |
|
# run: |
|
||||||
if [ "$CLOC_STATUS" = "failure" ]; then
|
# if [ "$CLOC_STATUS" = "failure" ]; then
|
||||||
exit 1
|
# exit 1
|
||||||
elif [ "$ANDROID_STATUS" = "failure" ]; then
|
# elif [ "$ANDROID_STATUS" = "failure" ]; then
|
||||||
exit 1
|
# exit 1
|
||||||
elif [ "$F_DROID_STATUS" = "failure" ]; then
|
# elif [ "$F_DROID_STATUS" = "failure" ]; then
|
||||||
exit 1
|
# exit 1
|
||||||
elif [ "$IOS_STATUS" = "failure" ]; then
|
# elif [ "$IOS_STATUS" = "failure" ]; then
|
||||||
exit 1
|
# exit 1
|
||||||
elif [ "$CROWDIN_PUSH_STATUS" = "failure" ]; then
|
# elif [ "$CROWDIN_PUSH_STATUS" = "failure" ]; then
|
||||||
exit 1
|
# exit 1
|
||||||
fi
|
# fi
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
# - name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
# uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
|
||||||
if: failure()
|
# if: failure()
|
||||||
with:
|
# with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
# creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
# - name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
# id: retrieve-secrets
|
||||||
if: failure()
|
# if: failure()
|
||||||
env:
|
# env:
|
||||||
KEYVAULT: bitwarden-ci
|
# KEYVAULT: bitwarden-ci
|
||||||
SECRETS: |
|
# SECRETS: |
|
||||||
devops-alerts-slack-webhook-url
|
# devops-alerts-slack-webhook-url
|
||||||
run: |
|
# run: |
|
||||||
for i in ${SECRETS//,/ }
|
# for i in ${SECRETS//,/ }
|
||||||
do
|
# do
|
||||||
VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
|
# VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv)
|
||||||
echo "::add-mask::$VALUE"
|
# echo "::add-mask::$VALUE"
|
||||||
echo "$i=$VALUE" >> $GITHUB_OUTPUT
|
# echo "$i=$VALUE" >> $GITHUB_OUTPUT
|
||||||
done
|
# done
|
||||||
|
|
||||||
- name: Notify Slack on failure
|
# - name: Notify Slack on failure
|
||||||
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
|
# uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
|
||||||
if: failure()
|
# if: failure()
|
||||||
env:
|
# env:
|
||||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
# SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||||
with:
|
# with:
|
||||||
status: ${{ job.status }}
|
# status: ${{ job.status }}
|
||||||
|
|||||||
6
.github/workflows/crowdin-pull.yml
vendored
6
.github/workflows/crowdin-pull.yml
vendored
@@ -18,19 +18,19 @@ jobs:
|
|||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
|
||||||
with:
|
with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
|
secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase"
|
||||||
|
|
||||||
- name: Download translations
|
- name: Download translations
|
||||||
uses: crowdin/github-action@ecd7eb0ef6f3cfa16293c79e9cbc4bc5b5fd9c49 # v1.4.9
|
uses: crowdin/github-action@965d501f160af7b1f88aed4c29154b0caf1e94b9 # v1.9.0
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||||
|
|||||||
2
.github/workflows/enforce-labels.yml
vendored
2
.github/workflows/enforce-labels.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: Enforce Label
|
- name: Enforce Label
|
||||||
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # v2.2.2
|
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
|
||||||
with:
|
with:
|
||||||
BANNED_LABELS: "hold,needs-qa"
|
BANNED_LABELS: "hold,needs-qa"
|
||||||
BANNED_LABELS_DESCRIPTION: "PRs with the hold or needs-qa labels cannot be merged"
|
BANNED_LABELS_DESCRIPTION: "PRs with the hold or needs-qa labels cannot be merged"
|
||||||
|
|||||||
2
.github/workflows/pr-labeler.yml
vendored
2
.github/workflows/pr-labeler.yml
vendored
@@ -12,6 +12,6 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@ba790c862c380240c6d5e7427be5ace9a05c754b # v4.0.3
|
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
|
||||||
with:
|
with:
|
||||||
sync-labels: true
|
sync-labels: true
|
||||||
|
|||||||
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@@ -38,11 +38,11 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||||
|
|
||||||
- name: Check Release Version
|
- name: Check Release Version
|
||||||
id: version
|
id: version
|
||||||
uses: bitwarden/gh-actions/release-version-check@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/release-version-check@main
|
||||||
with:
|
with:
|
||||||
release-type: ${{ github.event.inputs.release_type }}
|
release-type: ${{ github.event.inputs.release_type }}
|
||||||
project-type: xamarin
|
project-type: xamarin
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
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:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Dry Run - Download all artifacts
|
- name: Dry Run - Download all artifacts
|
||||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
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:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||||
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01 # v1.9.0
|
uses: ncipollo/release-action@6c75be85e571768fa31b40abf38de58ba0397db5 # v1.13.0
|
||||||
with:
|
with:
|
||||||
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
|
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
|
||||||
./com.x8bit.bitwarden.apk/com.x8bit.bitwarden.apk,
|
./com.x8bit.bitwarden.apk/com.x8bit.bitwarden.apk,
|
||||||
@@ -126,11 +126,11 @@ jobs:
|
|||||||
if: inputs.fdroid_publish
|
if: inputs.fdroid_publish
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||||
|
|
||||||
- name: Download F-Droid .apk artifact
|
- name: Download F-Droid .apk artifact
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
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:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@@ -139,7 +139,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Dry Run - Download F-Droid .apk artifact
|
- name: Dry Run - Download F-Droid .apk artifact
|
||||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
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:
|
with:
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
workflow_conclusion: success
|
workflow_conclusion: success
|
||||||
@@ -147,9 +147,9 @@ jobs:
|
|||||||
name: com.x8bit.bitwarden-fdroid.apk
|
name: com.x8bit.bitwarden-fdroid.apk
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561 # v2.5.1
|
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||||
with:
|
with:
|
||||||
node-version: '10.x'
|
node-version: '16.x'
|
||||||
|
|
||||||
- name: Set up F-Droid server
|
- name: Set up F-Droid server
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
2
.github/workflows/stale-bot.yml
vendored
2
.github/workflows/stale-bot.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: 'Run stale action'
|
- name: 'Run stale action'
|
||||||
uses: actions/stale@3cc123766321e9f15a6676375c154ccffb12a358 # v5.0.0
|
uses: actions/stale@f7176fd3007623b69d27091f9b9d4ab7995f0a06 # v5.2.1
|
||||||
with:
|
with:
|
||||||
stale-issue-label: 'needs-reply'
|
stale-issue-label: 'needs-reply'
|
||||||
stale-pr-label: 'needs-changes'
|
stale-pr-label: 'needs-changes'
|
||||||
|
|||||||
18
.github/workflows/version-auto-bump.yml
vendored
18
.github/workflows/version-auto-bump.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
version_number: ${{ steps.version.outputs.new-version }}
|
version_number: ${{ steps.version.outputs.new-version }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Branch
|
- name: Checkout Branch
|
||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||||
|
|
||||||
- name: Calculate bumped version
|
- name: Calculate bumped version
|
||||||
id: version
|
id: version
|
||||||
@@ -32,14 +32,8 @@ jobs:
|
|||||||
echo "new-version=$NEW_VER" >> $GITHUB_OUTPUT
|
echo "new-version=$NEW_VER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
trigger_version_bump:
|
trigger_version_bump:
|
||||||
name: "Version bump"
|
name: Bump version to ${{ needs.setup.outputs.version_number }}
|
||||||
runs-on: ubuntu-22.04
|
needs: setup
|
||||||
needs:
|
uses: ./.github/workflows/version-bump.yml
|
||||||
- setup
|
with:
|
||||||
steps:
|
version_number: ${{ needs.setup.outputs.version_number }}
|
||||||
- name: Bump version to ${{ needs.setup.outputs.version_number }}
|
|
||||||
uses: ./.github/workflows/version-bump.yml
|
|
||||||
secrets:
|
|
||||||
AZURE_PROD_KV_CREDENTIALS: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
|
||||||
with:
|
|
||||||
version_number: ${{ needs.setup.outputs.version_number }}
|
|
||||||
|
|||||||
21
.github/workflows/version-bump.yml
vendored
21
.github/workflows/version-bump.yml
vendored
@@ -12,9 +12,6 @@ on:
|
|||||||
version_number:
|
version_number:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
secrets:
|
|
||||||
AZURE_PROD_KV_CREDENTIALS:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
bump_version:
|
bump_version:
|
||||||
@@ -22,22 +19,22 @@ jobs:
|
|||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Branch
|
- name: Checkout Branch
|
||||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf # v1.4.3
|
uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
|
||||||
with:
|
with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
uses: bitwarden/gh-actions/get-keyvault-secrets@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
with:
|
with:
|
||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
|
secrets: "github-gpg-private-key, github-gpg-private-key-passphrase"
|
||||||
|
|
||||||
- name: Import GPG key
|
- name: Import GPG key
|
||||||
uses: crazy-max/ghaction-import-gpg@111c56156bcc6918c056dbef52164cfa583dc549 # v5.2.0
|
uses: crazy-max/ghaction-import-gpg@d6f3f49f3345e29369fe57596a3ca8f94c4d2ca7 # v5.4.0
|
||||||
with:
|
with:
|
||||||
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
|
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
|
||||||
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
||||||
@@ -48,31 +45,31 @@ jobs:
|
|||||||
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
|
run: git switch -c version_bump_${{ github.event.inputs.version_number }}
|
||||||
|
|
||||||
- name: Bump Version - Android XML
|
- name: Bump Version - Android XML
|
||||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ github.event.inputs.version_number }}
|
version: ${{ github.event.inputs.version_number }}
|
||||||
file_path: "./src/Android/Properties/AndroidManifest.xml"
|
file_path: "./src/Android/Properties/AndroidManifest.xml"
|
||||||
|
|
||||||
- name: Bump Version - iOS.Autofill
|
- name: Bump Version - iOS.Autofill
|
||||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ github.event.inputs.version_number }}
|
version: ${{ github.event.inputs.version_number }}
|
||||||
file_path: "./src/iOS.Autofill/Info.plist"
|
file_path: "./src/iOS.Autofill/Info.plist"
|
||||||
|
|
||||||
- name: Bump Version - iOS.Extension
|
- name: Bump Version - iOS.Extension
|
||||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ github.event.inputs.version_number }}
|
version: ${{ github.event.inputs.version_number }}
|
||||||
file_path: "./src/iOS.Extension/Info.plist"
|
file_path: "./src/iOS.Extension/Info.plist"
|
||||||
|
|
||||||
- name: Bump Version - iOS.ShareExtension
|
- name: Bump Version - iOS.ShareExtension
|
||||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ github.event.inputs.version_number }}
|
version: ${{ github.event.inputs.version_number }}
|
||||||
file_path: "./src/iOS.ShareExtension/Info.plist"
|
file_path: "./src/iOS.ShareExtension/Info.plist"
|
||||||
|
|
||||||
- name: Bump Version - iOS
|
- name: Bump Version - iOS
|
||||||
uses: bitwarden/gh-actions/version-bump@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ github.event.inputs.version_number }}
|
version: ${{ github.event.inputs.version_number }}
|
||||||
file_path: "./src/iOS/Info.plist"
|
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:
|
jobs:
|
||||||
call-workflow:
|
call-workflow:
|
||||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@34ecb67b2a357795dc893549df0795e7383ff50f
|
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,6 +31,7 @@ Components/
|
|||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
!src/lib/x86/
|
!src/lib/x86/
|
||||||
|
!src/App/Platforms/Android/lib/x86/
|
||||||
build/
|
build/
|
||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
# Bitwarden Mobile Application
|
# Bitwarden Mobile Application
|
||||||
|
|
||||||
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://mobileapp.bitwarden.com/fdroid/" target="_blank"><img alt="Get it on Google Play" src="https://i.imgur.com/HDicnzz.png" width="154" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a>
|
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank"><img alt="Get it on Google Play" src="https://imgur.com/YQzmZi9.png" width="153" height="46"></a> <a href="https://mobileapp.bitwarden.com/fdroid/" target="_blank"><img alt="Get it on F-Droid" src="https://i.imgur.com/HDicnzz.png" width="154" height="46"></a> <a href="https://itunes.apple.com/us/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank"><img src="https://imgur.com/GdGqPMY.png" width="135" height="40"></a>
|
||||||
|
|
||||||
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
|
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
|
||||||
|
|
||||||
|
|||||||
@@ -1,471 +1,158 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 16.0.29009.5
|
VisualStudioVersion = 17.8.34112.27
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{971FDF07-E288-4239-B47A-E9E7E912193B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{4B8A8C41-9820-4341-974C-41E65B7F4366}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "test\Playground\Playground.csproj", "{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D10CA4A9-F866-40E1-B658-F69051236C71}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8904C536-C67D-420F-9971-51B26574C3AA}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD-9047-4C3C-8EA3-D972D6622D84}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76690DFB-B7F4-4781-83E4-113FDC450AFE}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
.gitignore = .gitignore
|
|
||||||
.github\workflows\build.yml = .github\workflows\build.yml
|
|
||||||
CONTRIBUTING.md = CONTRIBUTING.md
|
|
||||||
crowdin.yml = crowdin.yml
|
|
||||||
README.md = README.md
|
|
||||||
SECURITY.md = SECURITY.md
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj", "{599E0201-420A-4C3E-A7BA-5349F72E0B15}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\iOS.ShareExtension\iOS.ShareExtension.csproj", "{F8C3F648-EA5A-4719-8005-85D1690B1655}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\iOS.ShareExtension\iOS.ShareExtension.csproj", "{F8C3F648-EA5A-4719-8005-85D1690B1655}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{83449CC4-1F76-4CFE-92B1-D2E13A62506F}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
|
||||||
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
|
||||||
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
|
||||||
AppStore|Any CPU = AppStore|Any CPU
|
|
||||||
AppStore|iPhone = AppStore|iPhone
|
|
||||||
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|iPhone = Debug|iPhone
|
|
||||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
|
||||||
FDroid|Any CPU = FDroid|Any CPU
|
|
||||||
FDroid|iPhone = FDroid|iPhone
|
|
||||||
FDroid|iPhoneSimulator = FDroid|iPhoneSimulator
|
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|iPhone = Release|iPhone
|
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||||
|
Debug|iPhone = Debug|iPhone
|
||||||
|
Release|iPhone = Release|iPhone
|
||||||
|
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
||||||
|
AppStore|iPhone = AppStore|iPhone
|
||||||
|
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
||||||
|
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Build.0 = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Deploy.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Deploy.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Deploy.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Build.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Deploy.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.ActiveCfg = AppStore|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.Build.0 = AppStore|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.ActiveCfg = FDroid|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.Build.0 = FDroid|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.Build.0 = FDroid|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|Any CPU.ActiveCfg = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.ActiveCfg = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.Build.0 = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.Build.0 = AppStore|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.Build.0 = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|iPhone
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.Build.0 = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.Build.0 = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.Build.0 = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|Any CPU.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{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
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
|
||||||
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
|
||||||
{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}
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
|
SolutionGuid = {3B3A9B6C-D325-4BB3-97D3-8070630C5D3B}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
|
Policies = $0
|
||||||
|
$0.DotNetNamingPolicy = $1
|
||||||
|
$1.DirectoryNamespaceAssociation = PrefixedHierarchical
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
44
build.cake
44
build.cake
@@ -67,7 +67,7 @@ Task("UpdateAndroidManifest")
|
|||||||
.Does(()=>
|
.Does(()=>
|
||||||
{
|
{
|
||||||
var buildVariant = GetVariant();
|
var buildVariant = GetVariant();
|
||||||
var manifestPath = Path.Combine(_slnPath, "src", "Android", "Properties", "AndroidManifest.xml");
|
var manifestPath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "AndroidManifest.xml");
|
||||||
|
|
||||||
// Cake.AndroidAppManifest doesn't currently enable us to access nested items so, quick (not ideal) fix:
|
// Cake.AndroidAppManifest doesn't currently enable us to access nested items so, quick (not ideal) fix:
|
||||||
var manifestText = FileReadText(manifestPath);
|
var manifestText = FileReadText(manifestPath);
|
||||||
@@ -119,26 +119,26 @@ Task("UpdateAndroidCodeFiles")
|
|||||||
//We're not using _androidPackageName here because the codefile is currently slightly different string than the one in AndroidManifest.xml
|
//We're not using _androidPackageName here because the codefile is currently slightly different string than the one in AndroidManifest.xml
|
||||||
var keyName = "com.8bit.bitwarden";
|
var keyName = "com.8bit.bitwarden";
|
||||||
var fixedPackageName = buildVariant.AndroidPackageName.Replace("x8bit", "8bit");
|
var fixedPackageName = buildVariant.AndroidPackageName.Replace("x8bit", "8bit");
|
||||||
var filePath = Path.Combine(_slnPath, "src", "Android", "Services", "BiometricService.cs");
|
var filePath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "BiometricService.cs");
|
||||||
ReplaceInFile(filePath, keyName, fixedPackageName);
|
ReplaceInFile(filePath, keyName, fixedPackageName);
|
||||||
|
|
||||||
var packageFileList = new string[] {
|
var packageFileList = new string[] {
|
||||||
Path.Combine(_slnPath, "src", "Android", "MainActivity.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainActivity.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "MainApplication.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainApplication.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Constants.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Constants.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Accessibility", "AccessibilityService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Accessibility", "AccessibilityService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillHelpers.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillHelpers.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "EventUploadReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "EventUploadReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "PackageReplacedReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "PackageReplacedReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Services", "DeviceActionService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "DeviceActionService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Services", "FileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "FileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Tiles", "AutofillTileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "AutofillTileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Tiles", "GeneratorTileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "GeneratorTileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Tiles", "MyVaultTileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "MyVaultTileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "google-services.json"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "google-services.json"),
|
||||||
Path.Combine(_slnPath, "store", "google", "Publisher", "Program.cs"),
|
Path.Combine(_slnPath, "store", "google", "Publisher", "Program.cs"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ Task("UpdateAndroidCodeFiles")
|
|||||||
}
|
}
|
||||||
|
|
||||||
var labelFileList = new string[] {
|
var labelFileList = new string[] {
|
||||||
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"),
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach(string path in labelFileList)
|
foreach(string path in labelFileList)
|
||||||
@@ -315,7 +315,7 @@ private void UpdateAppleIcons(string target, string appiconsetTarget)
|
|||||||
|
|
||||||
Task("UpdateiOSIcons")
|
Task("UpdateiOSIcons")
|
||||||
.Does(()=>{
|
.Does(()=>{
|
||||||
UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset"));
|
UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset"));
|
||||||
UpdateAppleIcons("watch", Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden WatchKit App", "Assets.xcassets", "AppIcon.appiconset"));
|
UpdateAppleIcons("watch", Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden WatchKit App", "Assets.xcassets", "AppIcon.appiconset"));
|
||||||
// TODO: Update complication icons when they start working
|
// TODO: Update complication icons when they start working
|
||||||
});
|
});
|
||||||
@@ -324,8 +324,8 @@ Task("UpdateiOSPlist")
|
|||||||
.IsDependentOn("GetGitInfo")
|
.IsDependentOn("GetGitInfo")
|
||||||
.Does(()=> {
|
.Does(()=> {
|
||||||
var buildVariant = GetVariant();
|
var buildVariant = GetVariant();
|
||||||
var infoPath = Path.Combine(_slnPath, "src", "iOS", "Info.plist");
|
var infoPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Info.plist");
|
||||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS", "Entitlements.plist");
|
var entitlementsPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Entitlements.plist");
|
||||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
|
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
|
||||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
||||||
});
|
});
|
||||||
|
|||||||
12
crowdin.yml
12
crowdin.yml
@@ -38,3 +38,15 @@ files:
|
|||||||
pt-PT: pt-PT
|
pt-PT: pt-PT
|
||||||
en-GB: en-GB
|
en-GB: en-GB
|
||||||
en-IN: en-IN
|
en-IN: en-IN
|
||||||
|
- source: "/src/watchOS/bitwarden/bitwarden WatchKit Extension/Localization/en.lproj/Localizable.strings"
|
||||||
|
dest: "/src/watchOS/bitwarden/bitwarden WatchKit Extension/Localization/en.lproj/%original_file_name%"
|
||||||
|
translation: "/src/watchOS/bitwarden/bitwarden WatchKit Extension/Localization//%two_letters_code%.lproj/%original_file_name%"
|
||||||
|
update_option: update_as_unapproved
|
||||||
|
languages_mapping:
|
||||||
|
two_letters_code:
|
||||||
|
zh-CN: zh-Hans
|
||||||
|
zh-TW: zh-Hant
|
||||||
|
pt-BR: pt-BR
|
||||||
|
pt-PT: pt-PT
|
||||||
|
en-GB: en-GB
|
||||||
|
en-IN: en-IN
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
<?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>
|
|
||||||
<ProjectGuid>{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}</ProjectGuid>
|
|
||||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<RootNamespace>Bit.Droid</RootNamespace>
|
|
||||||
<AssemblyName>BitwardenAndroid</AssemblyName>
|
|
||||||
<AndroidApplication>True</AndroidApplication>
|
|
||||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
|
||||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
|
||||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
|
||||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
|
||||||
<TargetFrameworkVersion>v13.0</TargetFrameworkVersion>
|
|
||||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
|
||||||
<NuGetPackageImportStamp>
|
|
||||||
</NuGetPackageImportStamp>
|
|
||||||
</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>3</WarningLevel>
|
|
||||||
<AndroidSupportedAbis />
|
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugSymbols>false</DebugSymbols>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
|
||||||
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
|
|
||||||
<DebugSymbols>false</DebugSymbols>
|
|
||||||
<OutputPath>bin\FDroid\</OutputPath>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<DefineConstants>FDROID</DefineConstants>
|
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
|
||||||
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Mono.Android" />
|
|
||||||
<Reference Include="Mono.Android.Export" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="System.Net.Http" Condition="'$(Configuration)'=='FDroid'" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Plugin.CurrentActivity">
|
|
||||||
<Version>2.1.0.4</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Portable.BouncyCastle">
|
|
||||||
<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.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.5</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Xamarin.Firebase.Messaging">
|
|
||||||
<Version>123.1.1.1</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<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.3</Version>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Accessibility\AccessibilityActivity.cs" />
|
|
||||||
<Compile Include="Accessibility\AccessibilityHelpers.cs" />
|
|
||||||
<Compile Include="Accessibility\Credentials.cs" />
|
|
||||||
<Compile Include="Accessibility\AccessibilityService.cs" />
|
|
||||||
<Compile Include="Accessibility\Browser.cs" />
|
|
||||||
<Compile Include="Accessibility\NodeList.cs" />
|
|
||||||
<Compile Include="Accessibility\KnownUsernameField.cs" />
|
|
||||||
<Compile Include="Autofill\AutofillConstants.cs" />
|
|
||||||
<Compile Include="Autofill\AutofillHelpers.cs" />
|
|
||||||
<Compile Include="Autofill\AutofillService.cs" />
|
|
||||||
<Compile Include="Autofill\AutofillExternalSelectionActivity.cs" />
|
|
||||||
<Compile Include="Autofill\Field.cs" />
|
|
||||||
<Compile Include="Autofill\FieldCollection.cs" />
|
|
||||||
<Compile Include="Autofill\FilledItem.cs" />
|
|
||||||
<Compile Include="Autofill\Parser.cs" />
|
|
||||||
<Compile Include="Autofill\SavedItem.cs" />
|
|
||||||
<Compile Include="Effects\FabShadowEffect.cs" />
|
|
||||||
<Compile Include="Effects\FixedSizeEffect.cs" />
|
|
||||||
<Compile Include="Effects\TabBarEffect.cs" />
|
|
||||||
<Compile Include="Push\FirebaseMessagingService.cs" />
|
|
||||||
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
|
|
||||||
<Compile Include="Receivers\RestrictionsChangedReceiver.cs" />
|
|
||||||
<Compile Include="Receivers\EventUploadReceiver.cs" />
|
|
||||||
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
|
|
||||||
<Compile Include="Renderers\ExtendedGridRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\ExtendedDatePickerRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\ExtendedStackLayoutRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\ExtendedStepperRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\CustomSwitchRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\ExtendedTimePickerRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\ExtendedSliderRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\CustomEditorRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\CustomPickerRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\CustomEntryRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
|
|
||||||
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
|
||||||
<Compile Include="Services\AndroidPushNotificationService.cs" />
|
|
||||||
<Compile Include="Services\AndroidLogService.cs" />
|
|
||||||
<Compile Include="MainApplication.cs" />
|
|
||||||
<Compile Include="MainActivity.cs" />
|
|
||||||
<Compile Include="Resources\Resource.designer.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<Compile Include="Services\BiometricService.cs" />
|
|
||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
|
||||||
<Compile Include="Services\DeviceActionService.cs" />
|
|
||||||
<Compile Include="Services\LocalizeService.cs" />
|
|
||||||
<Compile Include="Tiles\AutofillTileService.cs" />
|
|
||||||
<Compile Include="Tiles\GeneratorTileService.cs" />
|
|
||||||
<Compile Include="Tiles\MyVaultTileService.cs" />
|
|
||||||
<Compile Include="Utilities\AndroidHelpers.cs" />
|
|
||||||
<Compile Include="Utilities\ThemeHelpers.cs" />
|
|
||||||
<Compile Include="WebAuthCallbackActivity.cs" />
|
|
||||||
<Compile Include="Renderers\SelectableLabelRenderer.cs" />
|
|
||||||
<Compile Include="Services\ClipboardService.cs" />
|
|
||||||
<Compile Include="Utilities\IntentExtensions.cs" />
|
|
||||||
<Compile Include="Renderers\CustomPageRenderer.cs" />
|
|
||||||
<Compile Include="Effects\NoEmojiKeyboardEffect.cs" />
|
|
||||||
<Compile Include="Receivers\NotificationDismissReceiver.cs" />
|
|
||||||
<Compile Include="Services\FileService.cs" />
|
|
||||||
<Compile Include="Services\AutofillHandler.cs" />
|
|
||||||
<Compile Include="Constants.cs" />
|
|
||||||
<Compile Include="Effects\RemoveFontPaddingEffect.cs" />
|
|
||||||
<Compile Include="Services\WatchDeviceService.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidAsset Include="Assets\bwi-font.ttf" />
|
|
||||||
<AndroidAsset Include="Assets\RobotoMono_Regular.ttf" />
|
|
||||||
<AndroidAsset Include="Assets\MaterialIcons_Regular.ttf" />
|
|
||||||
<None Include="8bit.keystore.enc" />
|
|
||||||
<GoogleServicesJson Include="google-services.json" />
|
|
||||||
<GoogleServicesJson Include="google-services.json.enc" />
|
|
||||||
<None Include="fdroid-keystore.jks.enc" />
|
|
||||||
<AndroidNativeLibrary Include="lib\arm64-v8a\libargon2.so" />
|
|
||||||
<AndroidNativeLibrary Include="lib\armeabi-v7a\libargon2.so" />
|
|
||||||
<AndroidNativeLibrary Include="lib\x86\libargon2.so" />
|
|
||||||
<AndroidNativeLibrary Include="lib\x86_64\libargon2.so" />
|
|
||||||
<None Include="Properties\AndroidManifest.xml" />
|
|
||||||
<None Include="upload-keystore.jks.enc" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\logo_legacy.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\logo_white_legacy.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\logo_legacy.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\logo_white_legacy.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\logo_legacy.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\logo_white_legacy.png" />
|
|
||||||
<AndroidResource Include="Resources\drawable\card.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\cog_environment.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\cog_settings.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\icon.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\ic_launcher_foreground.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\ic_launcher_monochrome.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\ic_warning.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\id.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\info.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\list_item_bg.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\lock.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\login.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\logo.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\logo_white.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\send.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\pencil.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\plus.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\generate.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\search.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\shield.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable-v23\splash_screen.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable-v23\splash_screen_dark.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\switch_thumb.xml" />
|
|
||||||
<AndroidResource Include="Resources\layout\progress_dialog_layout.xml" />
|
|
||||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
|
||||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher_round.xml" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-hdpi\ic_launcher_round.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-mdpi\ic_launcher_round.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
|
||||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
|
||||||
<AndroidResource Include="Resources\values-night\styles.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\styles.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\colors.xml" />
|
|
||||||
<AndroidResource Include="Resources\values\manifest.xml" />
|
|
||||||
<AndroidResource Include="Resources\values-v30\manifest.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable-v26\splash_screen_round.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\logo_rounded.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable-night-v26\splash_screen_round.xml" />
|
|
||||||
<AndroidResource Include="Resources\drawable\ic_notification.xml">
|
|
||||||
<SubType></SubType>
|
|
||||||
<Generator></Generator>
|
|
||||||
</AndroidResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\splash_screen.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\App\App.csproj">
|
|
||||||
<Project>{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}</Project>
|
|
||||||
<Name>App</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\Core\Core.csproj">
|
|
||||||
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
|
|
||||||
<Name>Core</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\xml\accessibilityservice.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\xml\autofillservice.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\xml\filepaths.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\xml\network_security_config.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\values\strings.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\values\ic_launcher_background.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\layout\autofill_listitem.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-hdpi\yubikey.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xhdpi\yubikey.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable-xxhdpi\yubikey.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\slider_thumb.xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\drawable\splash_screen_dark.xml">
|
|
||||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</AndroidResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\values\dimens.xml">
|
|
||||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</AndroidResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AndroidResource Include="Resources\xml\app_restrictions.xml">
|
|
||||||
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</AndroidResource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Resources\values-v30\" />
|
|
||||||
<Folder Include="Resources\drawable-v26\" />
|
|
||||||
<Folder Include="Resources\drawable-night-v26\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
|
||||||
</Project>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Bit.Droid
|
|
||||||
{
|
|
||||||
public static class Constants
|
|
||||||
{
|
|
||||||
public const string PACKAGE_NAME = "com.x8bit.bitwarden";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Android.Graphics.Drawables;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportEffect(typeof(FabShadowEffect), "FabShadowEffect")]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class FabShadowEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached ()
|
|
||||||
{
|
|
||||||
if (Control is Android.Widget.Button button)
|
|
||||||
{
|
|
||||||
var gd = new GradientDrawable();
|
|
||||||
gd.SetColor(ThemeHelpers.FabColor);
|
|
||||||
gd.SetCornerRadius(100);
|
|
||||||
|
|
||||||
button.SetBackground(gd);
|
|
||||||
button.Elevation = 6;
|
|
||||||
button.TranslationZ = 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportEffect(typeof(FixedSizeEffect), "FixedSizeEffect")]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class FixedSizeEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached()
|
|
||||||
{
|
|
||||||
if (Element is Label label && Control is TextView textView)
|
|
||||||
{
|
|
||||||
textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportEffect(typeof(RemoveFontPaddingEffect), nameof(RemoveFontPaddingEffect))]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class RemoveFontPaddingEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached()
|
|
||||||
{
|
|
||||||
if (Control is TextView textView)
|
|
||||||
{
|
|
||||||
textView.SetIncludeFontPadding(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Android.Views;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Google.Android.Material.BottomNavigation;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ResolutionGroupName("Bitwarden")]
|
|
||||||
[assembly: ExportEffect(typeof(TabBarEffect), "TabBarEffect")]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class TabBarEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached()
|
|
||||||
{
|
|
||||||
if (!(Container.GetChildAt(0) is ViewGroup layout))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bottomNavigationView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityLabeled;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("BitwardenAndroid")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("Bitwarden Inc.")]
|
|
||||||
[assembly: AssemblyProduct("Bitwarden")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomEditorRenderer : EditorRenderer
|
|
||||||
{
|
|
||||||
public CustomEditorRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
// Workaround for issue described here:
|
|
||||||
// https://github.com/xamarin/Xamarin.Forms/issues/8291#issuecomment-617456651
|
|
||||||
protected override void OnAttachedToWindow()
|
|
||||||
{
|
|
||||||
base.OnAttachedToWindow();
|
|
||||||
EditText.Enabled = false;
|
|
||||||
EditText.Enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBorderColor();
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
|
||||||
Control.PaddingBottom + 20);
|
|
||||||
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
|
||||||
(ImeAction)ImeFlags.NoExtractUi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Entry.TextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBorderColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBorderColor()
|
|
||||||
{
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
var states = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
|
||||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
|
||||||
};
|
|
||||||
var colors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.PrimaryColor,
|
|
||||||
ThemeHelpers.MutedColor
|
|
||||||
};
|
|
||||||
Control.BackgroundTintList = new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Android.Graphics;
|
|
||||||
using Android.Text;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomEntryRenderer : EntryRenderer
|
|
||||||
{
|
|
||||||
public CustomEntryRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBorderColor();
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
|
||||||
Control.PaddingBottom + 20);
|
|
||||||
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
|
||||||
(ImeAction)ImeFlags.NoExtractUi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for bug preventing long-press -> copy/paste on Android 11
|
|
||||||
// See https://issuetracker.google.com/issues/37095917
|
|
||||||
protected override void OnAttachedToWindow()
|
|
||||||
{
|
|
||||||
base.OnAttachedToWindow();
|
|
||||||
Control.Enabled = false;
|
|
||||||
Control.Enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for failure to disable text prediction on non-password fields
|
|
||||||
// see https://github.com/xamarin/Xamarin.Forms/issues/10857
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
// Check if changed property is "IsPassword", otherwise ignore
|
|
||||||
if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
|
|
||||||
{
|
|
||||||
// Check if field type is text, otherwise ignore (numeric passwords, etc.)
|
|
||||||
EditText.InputType = Element.Keyboard.ToInputType();
|
|
||||||
bool isText = (EditText.InputType & InputTypes.ClassText) == InputTypes.ClassText,
|
|
||||||
isNumber = (EditText.InputType & InputTypes.ClassNumber) == InputTypes.ClassNumber;
|
|
||||||
if (isText || isNumber)
|
|
||||||
{
|
|
||||||
if (Element.IsPassword)
|
|
||||||
{
|
|
||||||
// Element is a password field, set inputType to TextVariationPassword which disables
|
|
||||||
// predictive text by default
|
|
||||||
EditText.InputType = EditText.InputType |
|
|
||||||
(isText ? InputTypes.TextVariationPassword : InputTypes.NumberVariationPassword);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Element is not a password field, set inputType to TextVariationVisiblePassword to
|
|
||||||
// disable predictive text while still displaying the content.
|
|
||||||
EditText.InputType = EditText.InputType |
|
|
||||||
(isText ? InputTypes.TextVariationVisiblePassword : InputTypes.NumberVariationNormal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The workaround above forces a reset of the style properties, so we need to re-apply the font.
|
|
||||||
// see https://xamarin.github.io/bugzilla-archives/33/33666/bug.html
|
|
||||||
var typeface = Typeface.CreateFromAsset(Context.Assets, "RobotoMono_Regular.ttf");
|
|
||||||
if (Control is TextView label)
|
|
||||||
{
|
|
||||||
label.Typeface = typeface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBorderColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBorderColor()
|
|
||||||
{
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
var states = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
|
||||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
|
||||||
};
|
|
||||||
var colors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.PrimaryColor,
|
|
||||||
ThemeHelpers.MutedColor
|
|
||||||
};
|
|
||||||
Control.BackgroundTintList = new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Android.App;
|
|
||||||
using Android.Content;
|
|
||||||
using AndroidX.AppCompat.Widget;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomPageRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomPageRenderer : PageRenderer
|
|
||||||
{
|
|
||||||
public CustomPageRenderer(Context context) : base(context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
|
|
||||||
Activity context = (Activity)this.Context;
|
|
||||||
var toolbar = context.FindViewById<Toolbar>(Resource.Id.toolbar);
|
|
||||||
if(toolbar != null)
|
|
||||||
{
|
|
||||||
toolbar.NavigationContentDescription = AppResources.TapToGoBack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomPickerRenderer : PickerRenderer
|
|
||||||
{
|
|
||||||
public CustomPickerRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBorderColor();
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
|
||||||
Control.PaddingBottom + 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Picker.TextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBorderColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBorderColor()
|
|
||||||
{
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
var states = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
|
||||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
|
||||||
};
|
|
||||||
var colors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.PrimaryColor,
|
|
||||||
ThemeHelpers.MutedColor
|
|
||||||
};
|
|
||||||
Control.BackgroundTintList = new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomSearchBarRenderer : SearchBarRenderer
|
|
||||||
{
|
|
||||||
public CustomSearchBarRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var magId = Resources.GetIdentifier("android:id/search_mag_icon", null, null);
|
|
||||||
var magImage = (Android.Widget.ImageView)Control.FindViewById(magId);
|
|
||||||
magImage.LayoutParameters = new Android.Widget.LinearLayout.LayoutParams(0, 0);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
Control.SetImeOptions(Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
|
||||||
(ImeAction)ImeFlags.NoExtractUi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using Android.OS;
|
|
||||||
using AndroidX.Core.Content.Resources;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Switch), typeof(CustomSwitchRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomSwitchRenderer : SwitchRenderer
|
|
||||||
{
|
|
||||||
public CustomSwitchRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Switch.OnColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateColors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateColors()
|
|
||||||
{
|
|
||||||
if (Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
|
|
||||||
{
|
|
||||||
// Android 5.x doesn't support ThumbTintList, and using SwitchCompat on every version after 5.x
|
|
||||||
// doesn't apply tinting the way we want. Let 5.x to do its own thing here.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
Control.SetHintTextColor(ThemeHelpers.MutedColor);
|
|
||||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.switch_thumb, null);
|
|
||||||
if (t is GradientDrawable thumb)
|
|
||||||
{
|
|
||||||
Control.ThumbDrawable = thumb;
|
|
||||||
}
|
|
||||||
var thumbStates = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateChecked }, // checked
|
|
||||||
new[] { -Android.Resource.Attribute.StateChecked }, // unchecked
|
|
||||||
};
|
|
||||||
var thumbColors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.SwitchOnColor,
|
|
||||||
ThemeHelpers.SwitchThumbColor
|
|
||||||
};
|
|
||||||
Control.ThumbTintList = new ColorStateList(thumbStates, thumbColors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Pages;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Google.Android.Material.BottomNavigation;
|
|
||||||
using Google.Android.Material.Navigation;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
using Xamarin.Forms.Platform.Android.AppCompat;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomTabbedRenderer : TabbedPageRenderer, NavigationBarView.IOnItemReselectedListener
|
|
||||||
{
|
|
||||||
private TabbedPage _page;
|
|
||||||
|
|
||||||
public CustomTabbedRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (e.NewElement != null)
|
|
||||||
{
|
|
||||||
_page = e.NewElement;
|
|
||||||
GetBottomNavigationView()?.SetOnItemReselectedListener(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_page = e.OldElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BottomNavigationView GetBottomNavigationView()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < ViewGroup.ChildCount; i++)
|
|
||||||
{
|
|
||||||
var childView = ViewGroup.GetChildAt(i);
|
|
||||||
if (childView is ViewGroup viewGroup)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < viewGroup.ChildCount; j++)
|
|
||||||
{
|
|
||||||
var childRelativeLayoutView = viewGroup.GetChildAt(j);
|
|
||||||
if (childRelativeLayoutView is BottomNavigationView bottomNavigationView)
|
|
||||||
{
|
|
||||||
return bottomNavigationView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnNavigationItemReselected(IMenuItem item)
|
|
||||||
{
|
|
||||||
if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
|
|
||||||
{
|
|
||||||
if (_page is TabsPage tabsPage)
|
|
||||||
{
|
|
||||||
tabsPage.OnPageReselected();
|
|
||||||
}
|
|
||||||
Device.BeginInvokeOnMainThread(async () => await _page.CurrentPage.Navigation.PopToRootAsync());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedDatePickerRenderer : DatePickerRenderer
|
|
||||||
{
|
|
||||||
public ExtendedDatePickerRenderer(Context context)
|
|
||||||
: base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (Control != null && Element is ExtendedDatePicker element)
|
|
||||||
{
|
|
||||||
// center text
|
|
||||||
Control.Gravity = GravityFlags.CenterHorizontal;
|
|
||||||
|
|
||||||
// use placeholder until NullableDate set
|
|
||||||
if (!element.NullableDate.HasValue)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == DatePicker.DateProperty.PropertyName ||
|
|
||||||
e.PropertyName == DatePicker.FormatProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedDatePicker element)
|
|
||||||
{
|
|
||||||
if (Element.Format == element.PlaceHolder)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedGrid), typeof(ExtendedGridRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedGridRenderer : ViewRenderer
|
|
||||||
{
|
|
||||||
public ExtendedGridRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(elementChangedEvent);
|
|
||||||
if (elementChangedEvent.NewElement != null)
|
|
||||||
{
|
|
||||||
SetBackgroundResource(Resource.Drawable.list_item_bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using AndroidX.Core.Content.Resources;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedSlider), typeof(ExtendedSliderRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedSliderRenderer : SliderRenderer
|
|
||||||
{
|
|
||||||
public ExtendedSliderRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == ExtendedSlider.ThumbBorderColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateColor()
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedSlider view)
|
|
||||||
{
|
|
||||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
|
|
||||||
if (t is GradientDrawable thumb)
|
|
||||||
{
|
|
||||||
if (view.ThumbColor == Color.Default)
|
|
||||||
{
|
|
||||||
thumb.SetColor(Color.White.ToAndroid());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
thumb.SetColor(view.ThumbColor.ToAndroid());
|
|
||||||
}
|
|
||||||
thumb.SetStroke(3, view.ThumbBorderColor.ToAndroid());
|
|
||||||
Control.SetThumb(thumb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedStackLayout), typeof(ExtendedStackLayoutRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedStackLayoutRenderer : ViewRenderer
|
|
||||||
{
|
|
||||||
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(elementChangedEvent);
|
|
||||||
if (elementChangedEvent.NewElement != null)
|
|
||||||
{
|
|
||||||
SetBackgroundResource(Resource.Drawable.list_item_bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Graphics;
|
|
||||||
using Android.OS;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedStepper), typeof(ExtendedStepperRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedStepperRenderer : StepperRenderer
|
|
||||||
{
|
|
||||||
public ExtendedStepperRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBgColor();
|
|
||||||
UpdateFgColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == ExtendedStepper.StepperBackgroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBgColor();
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == ExtendedStepper.StepperForegroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateFgColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBgColor()
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedStepper view)
|
|
||||||
{
|
|
||||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
|
|
||||||
{
|
|
||||||
Control.GetChildAt(0)?.Background?.SetColorFilter(
|
|
||||||
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
|
|
||||||
Control.GetChildAt(1)?.Background?.SetColorFilter(
|
|
||||||
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Control.GetChildAt(0)?.Background?.SetColorFilter(
|
|
||||||
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
|
|
||||||
Control.GetChildAt(1)?.Background?.SetColorFilter(
|
|
||||||
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateFgColor()
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedStepper view)
|
|
||||||
{
|
|
||||||
var btn0 = Control.GetChildAt(0) as Android.Widget.Button;
|
|
||||||
btn0?.SetTextColor(view.StepperForegroundColor.ToAndroid());
|
|
||||||
var btn1 = Control.GetChildAt(1) as Android.Widget.Button;
|
|
||||||
btn1?.SetTextColor(view.StepperForegroundColor.ToAndroid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedTimePicker), typeof(ExtendedTimePickerRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedTimePickerRenderer : TimePickerRenderer
|
|
||||||
{
|
|
||||||
public ExtendedTimePickerRenderer(Context context)
|
|
||||||
: base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (Control != null && Element is ExtendedTimePicker element)
|
|
||||||
{
|
|
||||||
// center text
|
|
||||||
Control.Gravity = GravityFlags.CenterHorizontal;
|
|
||||||
|
|
||||||
// use placeholder until NullableTime set
|
|
||||||
if (!element.NullableTime.HasValue)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == TimePicker.TimeProperty.PropertyName ||
|
|
||||||
e.PropertyName == TimePicker.FormatProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedTimePicker element)
|
|
||||||
{
|
|
||||||
if (Element.Format == element.PlaceHolder)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
using Android.Webkit;
|
|
||||||
using AWebkit = Android.Webkit;
|
|
||||||
using Java.Interop;
|
|
||||||
using Android.Content;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, AWebkit.WebView>
|
|
||||||
{
|
|
||||||
private const string JSFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
|
|
||||||
|
|
||||||
private readonly Context _context;
|
|
||||||
|
|
||||||
public HybridWebViewRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
|
|
||||||
if (Control == null)
|
|
||||||
{
|
|
||||||
var webView = new AWebkit.WebView(_context);
|
|
||||||
webView.Settings.JavaScriptEnabled = true;
|
|
||||||
webView.SetWebViewClient(new JSWebViewClient(string.Format("javascript: {0}", JSFunction)));
|
|
||||||
SetNativeControl(webView);
|
|
||||||
}
|
|
||||||
if (e.OldElement != null)
|
|
||||||
{
|
|
||||||
Control.RemoveJavascriptInterface("jsBridge");
|
|
||||||
var hybridWebView = e.OldElement as HybridWebView;
|
|
||||||
hybridWebView.Cleanup();
|
|
||||||
}
|
|
||||||
if (e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
|
|
||||||
Control.LoadUrl(Element.Uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
if (e.PropertyName == HybridWebView.UriProperty.PropertyName)
|
|
||||||
{
|
|
||||||
Control.LoadUrl(Element.Uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class JSBridge : Java.Lang.Object
|
|
||||||
{
|
|
||||||
private readonly WeakReference<HybridWebViewRenderer> _hybridWebViewRenderer;
|
|
||||||
|
|
||||||
public JSBridge(HybridWebViewRenderer hybridRenderer)
|
|
||||||
{
|
|
||||||
_hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
[JavascriptInterface]
|
|
||||||
[Export("invokeAction")]
|
|
||||||
public void InvokeAction(string data)
|
|
||||||
{
|
|
||||||
if (_hybridWebViewRenderer != null &&
|
|
||||||
_hybridWebViewRenderer.TryGetTarget(out HybridWebViewRenderer hybridRenderer))
|
|
||||||
{
|
|
||||||
hybridRenderer.Element.InvokeAction(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class JSWebViewClient : WebViewClient
|
|
||||||
{
|
|
||||||
private readonly string _javascript;
|
|
||||||
|
|
||||||
public JSWebViewClient(string javascript)
|
|
||||||
{
|
|
||||||
_javascript = javascript;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPageFinished(AWebkit.WebView view, string url)
|
|
||||||
{
|
|
||||||
base.OnPageFinished(view, url);
|
|
||||||
view.EvaluateJavascript(_javascript, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Android.Content;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(SelectableLabel), typeof(SelectableLabelRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class SelectableLabelRenderer : LabelRenderer
|
|
||||||
{
|
|
||||||
public SelectableLabelRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
Control.SetTextIsSelectable(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,444 +1,240 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFrameworks>net8.0-android;net8.0-ios</TargetFrameworks>
|
||||||
<RootNamespace>Bit.App</RootNamespace>
|
|
||||||
<AssemblyName>BitwardenApp</AssemblyName>
|
<!-- Uncomment to also build for Windows platform.-->
|
||||||
<Configurations>Debug;Release;FDroid</Configurations>
|
<!--<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>-->
|
||||||
|
|
||||||
|
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
|
||||||
|
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
||||||
|
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Bit.App</RootNamespace>
|
||||||
|
<UseMaui>true</UseMaui>
|
||||||
|
<SingleProject>true</SingleProject>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|
||||||
|
<!-- Display name -->
|
||||||
|
<ApplicationTitle>Bitwarden</ApplicationTitle>
|
||||||
|
|
||||||
|
<!-- App Identifier -->
|
||||||
|
<ApplicationId Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">com.8bit.bitwarden</ApplicationId>
|
||||||
|
<ApplicationId Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">com.x8bit.bitwarden</ApplicationId>
|
||||||
|
<ApplicationIdGuid>ccf4766c-a36c-4647-900c-0ea7d323ccc6</ApplicationIdGuid>
|
||||||
|
|
||||||
|
<!-- Versions -->
|
||||||
|
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
||||||
|
<ApplicationVersion>1</ApplicationVersion>
|
||||||
|
|
||||||
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
|
||||||
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||||
|
|
||||||
|
<ForceSimulatorX64ArchitectureInIDE>true</ForceSimulatorX64ArchitectureInIDE>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<DefineConstants Condition=" '$(CustomConstants)' != '' ">$(DefineConstants);$(CustomConstants)</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android|AnyCPU'">
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<AndroidEnableMultiDex>True</AndroidEnableMultiDex>
|
||||||
<DebugType>pdbonly</DebugType>
|
<UseInterpreter>False</UseInterpreter>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>True</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-android|AnyCPU'">
|
||||||
<ItemGroup>
|
<AndroidEnableMultiDex>True</AndroidEnableMultiDex>
|
||||||
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
|
<UseInterpreter>False</UseInterpreter>
|
||||||
<PackageReference Include="SkiaSharp.Views.Forms" Version="2.88.3" />
|
<DebugSymbols>False</DebugSymbols>
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit" Version="2.0.6" />
|
<RunAOTCompilation>False</RunAOTCompilation>
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
|
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||||
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
|
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2578" />
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
|
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
||||||
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
|
</PropertyGroup>
|
||||||
<PackageReference Include="MessagePack" Version="2.4.59" />
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
|
||||||
</ItemGroup>
|
<CreatePackage>false</CreatePackage>
|
||||||
|
<CodesignProvision>Automatic</CodesignProvision>
|
||||||
<ItemGroup>
|
<CodesignKey>iPhone Developer</CodesignKey>
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
|
||||||
</ItemGroup>
|
<MtouchInterpreter>all</MtouchInterpreter>
|
||||||
|
<MtouchLink>None</MtouchLink>
|
||||||
<ItemGroup>
|
<!--TODO: add argon2id load when library is built with the corresponding architecture for iOS Simulator-->
|
||||||
<Compile Update="Pages\Accounts\EnvironmentPage.xaml.cs">
|
</PropertyGroup>
|
||||||
<DependentUpon>EnvironmentPage.xaml</DependentUpon>
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(RuntimeIdentifier)'=='Debug|net8.0-ios|ios-arm64'">
|
||||||
</Compile>
|
<MtouchExtraArgs>-gcc_flags "-L$(ProjectDir)../../lib/ios -largon2 -force_load $(ProjectDir)../../lib/ios/libargon2.a"</MtouchExtraArgs>
|
||||||
<Compile Update="Pages\Accounts\HintPage.xaml.cs">
|
</PropertyGroup>
|
||||||
<DependentUpon>HintPage.xaml</DependentUpon>
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
|
||||||
</Compile>
|
<CreatePackage>false</CreatePackage>
|
||||||
<Compile Update="Pages\Accounts\LockPage.xaml.cs">
|
<CodesignProvision>Automatic:AppStore</CodesignProvision>
|
||||||
<DependentUpon>LockPage.xaml</DependentUpon>
|
<CodesignKey>iPhone Distribution</CodesignKey>
|
||||||
</Compile>
|
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
|
||||||
<Compile Update="Pages\Accounts\TwoFactorPage.xaml.cs">
|
<MtouchInterpreter>all</MtouchInterpreter>
|
||||||
<DependentUpon>TwoFactorPage.xaml</DependentUpon>
|
<MtouchLink>None</MtouchLink>
|
||||||
</Compile>
|
<MtouchExtraArgs>--weak-framework=NewsstandKit.framework/NewsstandKit --linkskip=LiteDB --linkskip=CsvHelper --linkskip=Core --linkskip=iOS.Core --linkskip=iOS.Autofill --linkskip=iOS.Extension --linkskip=iOS.ShareExtension --linkskip=App -gcc_flags "-L$(ProjectDir)../../lib/ios -largon2 -force_load $(ProjectDir)../../lib/ios/libargon2.a"</MtouchExtraArgs>
|
||||||
<Compile Update="Pages\Accounts\RegisterPage.xaml.cs">
|
</PropertyGroup>
|
||||||
<DependentUpon>RegisterPage.xaml</DependentUpon>
|
<ItemGroup>
|
||||||
</Compile>
|
<AndroidNativeLibrary Include="Platforms\Android\lib\arm64-v8a\libargon2.so" />
|
||||||
<Compile Update="Pages\Accounts\LoginPage.xaml.cs">
|
<AndroidNativeLibrary Include="Platforms\Android\lib\armeabi-v7a\libargon2.so" />
|
||||||
<DependentUpon>LoginPage.xaml</DependentUpon>
|
<AndroidNativeLibrary Include="Platforms\Android\lib\x86\libargon2.so" />
|
||||||
</Compile>
|
<AndroidNativeLibrary Include="Platforms\Android\lib\x86_64\libargon2.so" />
|
||||||
<Compile Update="Pages\Generator\GeneratorPage.xaml.cs">
|
</ItemGroup>
|
||||||
<DependentUpon>GeneratorPage.xaml</DependentUpon>
|
<ItemGroup>
|
||||||
</Compile>
|
<PackageReference Include="Camera.MAUI" Version="1.4.4" />
|
||||||
<Compile Update="Pages\Generator\GeneratorHistoryPage.xaml.cs">
|
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||||
<DependentUpon>GeneratorHistoryPage.xaml</DependentUpon>
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||||
</Compile>
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||||
<Compile Update="Pages\Settings\AutofillPage.xaml.cs">
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
<DependentUpon>AutofillPage.xaml</DependentUpon>
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
</Compile>
|
<PackageReference Include="MessagePack" Version="2.5.124" />
|
||||||
<Compile Update="Pages\Settings\ExtensionPage.xaml.cs">
|
<PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.5.124">
|
||||||
<DependentUpon>ExtensionPage.xaml</DependentUpon>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</Compile>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<Compile Update="Pages\Settings\AutofillServicesPage.xaml.cs">
|
</PackageReference>
|
||||||
<DependentUpon>AutofillServicesPage.xaml</DependentUpon>
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
</Compile>
|
<PackageReference Include="zxcvbn-core" Version="7.0.92" />
|
||||||
<Compile Update="Pages\Settings\FolderAddEditPage.xaml.cs">
|
<PackageReference Include="CommunityToolkit.Maui" Version="5.2.0" />
|
||||||
<DependentUpon>FolderAddEditPage.xaml</DependentUpon>
|
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
|
||||||
</Compile>
|
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.4-preview.84" />
|
||||||
<Compile Update="Pages\Settings\FoldersPage.xaml.cs">
|
<PackageReference Include="SkiaSharp.Views.Maui.Controls.Compatibility" Version="2.88.4-preview.84" />
|
||||||
<DependentUpon>FoldersPage.xaml</DependentUpon>
|
<PackageReference Include="FFImageLoadingCompat.Maui" Version="0.1.1" />
|
||||||
</Compile>
|
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="6.0.6" />
|
||||||
<Compile Update="Pages\Settings\ExportVaultPage.xaml.cs">
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||||
<DependentUpon>ExportVaultPage.xaml</DependentUpon>
|
<PackageReference Include="PCLCrypto" Version="2.1.40-alpha" />
|
||||||
</Compile>
|
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
||||||
<Compile Update="Pages\Settings\OptionsPage.xaml.cs">
|
</ItemGroup>
|
||||||
<DependentUpon>OptionsPage.xaml</DependentUpon>
|
<ItemGroup>
|
||||||
</Compile>
|
<Folder Include="Effects\" />
|
||||||
<Compile Update="Pages\Settings\SyncPage.xaml.cs">
|
<Folder Include="Resources\" />
|
||||||
<DependentUpon>SyncPage.xaml</DependentUpon>
|
<Folder Include="Resources\AppIcon\" />
|
||||||
</Compile>
|
<Folder Include="Resources\Splash\" />
|
||||||
<Compile Update="Pages\Vault\AttachmentsPage.xaml.cs">
|
<Folder Include="Platforms\Android\Accessibility\" />
|
||||||
<DependentUpon>AttachmentsPage.xaml</DependentUpon>
|
<Folder Include="Platforms\Android\Autofill\" />
|
||||||
</Compile>
|
<Folder Include="Platforms\Android\Push\" />
|
||||||
<Compile Update="Pages\Vault\AutofillCiphersPage.xaml.cs">
|
<Folder Include="Platforms\Android\Receivers\" />
|
||||||
<DependentUpon>AutofillCiphersPage.xaml</DependentUpon>
|
<Folder Include="Platforms\Android\Services\" />
|
||||||
</Compile>
|
<Folder Include="Platforms\Android\Tiles\" />
|
||||||
<Compile Update="Pages\Vault\CollectionsPage.xaml.cs">
|
<Folder Include="Platforms\Android\Utilities\" />
|
||||||
<DependentUpon>CollectionsPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||||
<Compile Update="Pages\Vault\ScanPage.xaml.cs">
|
<PackageReference Include="Plugin.CurrentActivity" Version="2.1.0.4" />
|
||||||
<DependentUpon>ScanPage.xaml</DependentUpon>
|
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
|
||||||
</Compile>
|
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx" Version="1.7.2.1" />
|
||||||
<Compile Update="Pages\Vault\SharePage.xaml.cs">
|
</ItemGroup>
|
||||||
<DependentUpon>SharePage.xaml</DependentUpon>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android' AND !$(DefineConstants.Contains(FDROID))">
|
||||||
</Compile>
|
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet" Version="118.0.1.5" />
|
||||||
<Compile Update="Pages\Vault\CiphersPage.xaml.cs">
|
<PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.2.2" />
|
||||||
<DependentUpon>CiphersPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="!$(DefineConstants.Contains(FDROID))">
|
||||||
<Compile Update="Pages\Vault\PasswordHistoryPage.xaml.cs">
|
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="5.0.3" />
|
||||||
<DependentUpon>PasswordHistoryPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup>
|
||||||
<Compile Update="Pages\Vault\CipherDetailsPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher.png" />
|
||||||
<DependentUpon>CipherDetailsPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||||
<Compile Update="Pages\Vault\CipherAddEditPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||||
<DependentUpon>CipherAddEditPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||||
<Compile Update="Pages\Settings\SettingsPage\SettingsPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher.png" />
|
||||||
<DependentUpon>SettingsPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher.png" />
|
||||||
<Compile Update="Pages\Vault\GroupingsPage\GroupingsPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||||
<DependentUpon>GroupingsPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||||
<Compile Update="Pages\Accounts\LoginSsoPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||||
<DependentUpon>LoginSsoPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||||
<SubType>Code</SubType>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||||
<Compile Update="Pages\Accounts\SetPasswordPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\logo_legacy.png" />
|
||||||
<DependentUpon>ResetMasterPasswordPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\yubikey.png" />
|
||||||
<SubType>Code</SubType>
|
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\logo_white_legacy.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\logo_legacy.png" />
|
||||||
<Compile Update="Pages\Send\SendGroupingsPage\SendGroupingsPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\yubikey.png" />
|
||||||
<DependentUpon>SendGroupingsPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\logo_white_legacy.png" />
|
||||||
<SubType>Code</SubType>
|
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\logo_legacy.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\yubikey.png" />
|
||||||
<Compile Remove="Pages\Accounts\AccountsPopupPage.xaml.cs" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\logo_white_legacy.png" />
|
||||||
<Compile Update="Pages\Accounts\LoginPasswordlessPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher.png" />
|
||||||
<DependentUpon>LoginPasswordlessPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
||||||
</Compile>
|
</ItemGroup>
|
||||||
<Compile Update="Pages\Accounts\LoginPasswordlessRequestPage.xaml.cs">
|
<ItemGroup>
|
||||||
<DependentUpon>LoginPasswordlessRequestPage.xaml</DependentUpon>
|
<ProjectReference Include="..\iOS.Core\iOS.Core.csproj" Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'" />
|
||||||
</Compile>
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
<ItemGroup>
|
<!-- App Icon -->
|
||||||
<Folder Include="Resources\" />
|
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
|
||||||
<Folder Include="Behaviors\" />
|
</ItemGroup>
|
||||||
<Folder Include="Lists\" />
|
<ItemGroup>
|
||||||
<Folder Include="Lists\ItemLayouts\" />
|
<MauiImage Include="Resources\cog_settings.svg">
|
||||||
<Folder Include="Lists\DataTemplateSelectors\" />
|
<BaseSize>24,24</BaseSize>
|
||||||
<Folder Include="Lists\ItemLayouts\CustomFields\" />
|
</MauiImage>
|
||||||
<Folder Include="Lists\ItemViewModels\" />
|
<MauiImage Include="Resources\ext_act.png" />
|
||||||
<Folder Include="Lists\ItemViewModels\CustomFields\" />
|
<MauiImage Include="Resources\ext_more.png" />
|
||||||
<Folder Include="Controls\AccountSwitchingOverlay\" />
|
<MauiImage Include="Resources\ext_use.png" />
|
||||||
<Folder Include="Utilities\AccountManagement\" />
|
<MauiImage Include="Resources\generate.svg">
|
||||||
<Folder Include="Controls\DateTime\" />
|
<BaseSize>24,24</BaseSize>
|
||||||
<Folder Include="Controls\IconLabelButton\" />
|
</MauiImage>
|
||||||
<Folder Include="Controls\PasswordStrengthProgressBar\" />
|
<MauiImage Include="Resources\info.svg">
|
||||||
</ItemGroup>
|
<BaseSize>24,24</BaseSize>
|
||||||
|
</MauiImage>
|
||||||
<ItemGroup>
|
<MauiImage Include="Resources\lock.svg">
|
||||||
<EmbeddedResource Remove="Pages\Accounts\AccountsPopupPage.xaml" />
|
<BaseSize>24,24</BaseSize>
|
||||||
</ItemGroup>
|
</MauiImage>
|
||||||
|
<MauiImage Include="Resources\login.svg">
|
||||||
<ItemGroup>
|
<BaseSize>24,24</BaseSize>
|
||||||
<Compile Update="Styles\Black.xaml.cs">
|
</MauiImage>
|
||||||
<DependentUpon>Black.xaml</DependentUpon>
|
<MauiImage Include="Resources\logo_white.png" />
|
||||||
</Compile>
|
<MauiImage Include="Resources\logo.png" />
|
||||||
<Compile Update="Styles\Nord.xaml.cs">
|
<MauiImage Include="Resources\more_vert.svg">
|
||||||
<DependentUpon>Nord.xaml</DependentUpon>
|
<BaseSize>24,24</BaseSize>
|
||||||
</Compile>
|
</MauiImage>
|
||||||
<Compile Update="Styles\Variables.xaml.cs">
|
<MauiImage Include="Resources\more.svg">
|
||||||
<DependentUpon>Variables.xaml</DependentUpon>
|
<BaseSize>24,24</BaseSize>
|
||||||
</Compile>
|
</MauiImage>
|
||||||
<Compile Update="Styles\Light.xaml.cs">
|
<MauiImage Include="Resources\plus.svg" TintColor="#FFFFFFFF">
|
||||||
<DependentUpon>Light.xaml</DependentUpon>
|
<BaseSize>24,24</BaseSize>
|
||||||
</Compile>
|
</MauiImage>
|
||||||
<Compile Update="Styles\Dark.xaml.cs">
|
<MauiImage Include="Resources\search.svg" TintColor="#FFFFFFFF">
|
||||||
<DependentUpon>Dark.xaml</DependentUpon>
|
<BaseSize>24,24</BaseSize>
|
||||||
</Compile>
|
</MauiImage>
|
||||||
<Compile Update="Styles\iOS.xaml.cs">
|
<MauiImage Include="Resources\send.svg">
|
||||||
<DependentUpon>iOS.xaml</DependentUpon>
|
<BaseSize>24,24</BaseSize>
|
||||||
</Compile>
|
</MauiImage>
|
||||||
<Compile Update="Styles\Android.xaml.cs">
|
<MauiImage Include="Resources\yubikey.png" />
|
||||||
<DependentUpon>Android.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\iOS.Autofill\iOS.Autofill.csproj">
|
||||||
|
<IsAppExtension>true</IsAppExtension>
|
||||||
<ItemGroup>
|
<IsWatchApp>false</IsWatchApp>
|
||||||
<Compile Update="Resources\AppResources.cs.Designer.cs">
|
</ProjectReference>
|
||||||
<DependentUpon>AppResources.cs.resx</DependentUpon>
|
<ProjectReference Include="..\iOS.Extension\iOS.Extension.csproj">
|
||||||
<DesignTime>True</DesignTime>
|
<IsAppExtension>true</IsAppExtension>
|
||||||
<AutoGen>True</AutoGen>
|
<IsWatchApp>false</IsWatchApp>
|
||||||
</Compile>
|
</ProjectReference>
|
||||||
<Compile Update="Resources\AppResources.da.Designer.cs">
|
<ProjectReference Include="..\iOS.ShareExtension\iOS.ShareExtension.csproj">
|
||||||
<DependentUpon>AppResources.da.resx</DependentUpon>
|
<IsAppExtension>true</IsAppExtension>
|
||||||
<DesignTime>True</DesignTime>
|
<IsWatchApp>false</IsWatchApp>
|
||||||
<AutoGen>True</AutoGen>
|
</ProjectReference>
|
||||||
</Compile>
|
</ItemGroup>
|
||||||
<Compile Update="Resources\AppResources.de.Designer.cs">
|
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0-ios'">
|
||||||
<DependentUpon>AppResources.de.resx</DependentUpon>
|
<WatchAppBuildPath Condition=" '$(Configuration)' == 'Debug' ">$(Home)/Library/Developer/Xcode/DerivedData/bitwarden-acgkbpwvmebfiofokotvoerzkqcl/Build/Products</WatchAppBuildPath>
|
||||||
<DesignTime>True</DesignTime>
|
<WatchAppBuildPath Condition=" '$(Configuration)' != 'Debug' ">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..'))/watchOS/bitwarden.xcarchive/Products/Applications/bitwarden.app/Watch</WatchAppBuildPath>
|
||||||
<AutoGen>True</AutoGen>
|
<WatchAppBundle>Bitwarden.app</WatchAppBundle>
|
||||||
</Compile>
|
<WatchAppConfiguration Condition="'$(RuntimeIdentifier)'!='ios-arm64'"> >watchsimulator</WatchAppConfiguration>
|
||||||
<Compile Update="Resources\AppResources.Designer.cs">
|
<WatchAppConfiguration Condition="'$(RuntimeIdentifier)'=='ios-arm64'"> >watchos</WatchAppConfiguration>
|
||||||
<DesignTime>True</DesignTime>
|
<WatchAppBundleFullPath Condition=" '$(Configuration)' == 'Debug' ">$(WatchAppBuildPath)/$(Configuration)-$(WatchAppConfiguration)/$(WatchAppBundle)</WatchAppBundleFullPath>
|
||||||
<AutoGen>True</AutoGen>
|
<WatchAppBundleFullPath Condition=" '$(Configuration)' != 'Debug' ">$(WatchAppBuildPath)/$(WatchAppBundle)</WatchAppBundleFullPath>
|
||||||
<DependentUpon>AppResources.resx</DependentUpon>
|
</PropertyGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND Exists('$(WatchAppBundleFullPath)') ">
|
||||||
<Compile Update="Resources\AppResources.es.Designer.cs">
|
<_ResolvedWatchAppReferences Include="$(WatchAppBundleFullPath)" />
|
||||||
<DependentUpon>AppResources.es.resx</DependentUpon>
|
</ItemGroup>
|
||||||
<DesignTime>True</DesignTime>
|
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND Exists('$(WatchAppBundleFullPath)') ">
|
||||||
<AutoGen>True</AutoGen>
|
<CreateAppBundleDependsOn>
|
||||||
</Compile>
|
_CopyWatchOS2AppsToBundle;
|
||||||
<Compile Update="Resources\AppResources.fi.Designer.cs">
|
$(CreateAppBundleDependsOn);
|
||||||
<DependentUpon>AppResources.fi.resx</DependentUpon>
|
</CreateAppBundleDependsOn>
|
||||||
<DesignTime>True</DesignTime>
|
</PropertyGroup>
|
||||||
<AutoGen>True</AutoGen>
|
<ItemGroup>
|
||||||
</Compile>
|
<GoogleServicesJson Include="Platforms\Android\google-services.json" />
|
||||||
<Compile Update="Resources\AppResources.fr.Designer.cs">
|
<GoogleServicesJson Include="Platforms\Android\google-services.json.enc" />
|
||||||
<DependentUpon>AppResources.fr.resx</DependentUpon>
|
</ItemGroup>
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.hi.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.hi.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.hr.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.hr.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.hu.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.hu.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.id.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.id.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.it.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.it.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.ja.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.ja.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.nl.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.nl.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.pl.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.pl.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.pt-BR.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.pt-BR.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.pt-PT.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.pt-PT.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.ro.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.ro.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.ru.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.ru.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.sk.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.sk.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.sv.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.sv.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.th.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.th.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.tr.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.tr.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.uk.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.uk.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.vi.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.vi.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.zh-Hans.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.zh-Hans.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.zh-Hant.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.zh-Hant.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.cs.resx">
|
|
||||||
<LastGenOutput>AppResources.cs.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.da.resx">
|
|
||||||
<LastGenOutput>AppResources.da.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.de.resx">
|
|
||||||
<LastGenOutput>AppResources.de.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.es.resx">
|
|
||||||
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.fi.resx">
|
|
||||||
<LastGenOutput>AppResources.fi.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.fr.resx">
|
|
||||||
<LastGenOutput>AppResources.fr.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.hi.resx">
|
|
||||||
<LastGenOutput>AppResources.hi.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.hr.resx">
|
|
||||||
<LastGenOutput>AppResources.hr.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.hu.resx">
|
|
||||||
<LastGenOutput>AppResources.hu.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.id.resx">
|
|
||||||
<LastGenOutput>AppResources.id.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.it.resx">
|
|
||||||
<LastGenOutput>AppResources.it.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.ja.resx">
|
|
||||||
<LastGenOutput>AppResources.ja.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.nl.resx">
|
|
||||||
<LastGenOutput>AppResources.nl.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.pl.resx">
|
|
||||||
<LastGenOutput>AppResources.pl.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.pt-BR.resx">
|
|
||||||
<LastGenOutput>AppResources.pt-BR.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.pt-PT.resx">
|
|
||||||
<LastGenOutput>AppResources.pt-PT.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.resx">
|
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
|
||||||
<LastGenOutput>AppResources.Designer.cs</LastGenOutput>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.ro.resx">
|
|
||||||
<LastGenOutput>AppResources.ro.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.ru.resx">
|
|
||||||
<LastGenOutput>AppResources.ru.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.sk.resx">
|
|
||||||
<LastGenOutput>AppResources.sk.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.sv.resx">
|
|
||||||
<LastGenOutput>AppResources.sv.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.th.resx">
|
|
||||||
<LastGenOutput>AppResources.th.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.tr.resx">
|
|
||||||
<LastGenOutput>AppResources.tr.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.uk.resx">
|
|
||||||
<LastGenOutput>AppResources.uk.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.vi.resx">
|
|
||||||
<LastGenOutput>AppResources.vi.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.zh-Hans.resx">
|
|
||||||
<LastGenOutput>AppResources.zh-Hans.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.zh-Hant.resx">
|
|
||||||
<LastGenOutput>AppResources.zh-Hant.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="Behaviors\" />
|
|
||||||
<None Remove="Xamarin.CommunityToolkit" />
|
|
||||||
<None Remove="Lists\" />
|
|
||||||
<None Remove="Lists\DataTemplates\" />
|
|
||||||
<None Remove="Lists\DataTemplateSelectors\" />
|
|
||||||
<None Remove="Lists\DataTemplates\CustomFields\" />
|
|
||||||
<None Remove="Lists\ItemViewModels\" />
|
|
||||||
<None Remove="Lists\ItemViewModels\CustomFields\" />
|
|
||||||
<None Remove="Controls\AccountSwitchingOverlay\" />
|
|
||||||
<None Remove="Utilities\AccountManagement\" />
|
|
||||||
<None Remove="Controls\DateTime\" />
|
|
||||||
<None Remove="Controls\IconLabelButton\" />
|
|
||||||
<None Remove="MessagePack" />
|
|
||||||
<None Remove="MessagePack.MSBuild.Tasks" />
|
|
||||||
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Xamarin.CommunityToolkit.Converters;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedCollectionView : CollectionView
|
|
||||||
{
|
|
||||||
public string ExtraDataForLogging { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SelectionChangedEventArgsConverter : BaseNullableConverterOneWay<SelectionChangedEventArgs, object>
|
|
||||||
{
|
|
||||||
public override object? ConvertFrom(SelectionChangedEventArgs? value)
|
|
||||||
{
|
|
||||||
return value?.CurrentSelection.FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedGrid : Grid
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using Bit.App.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedSearchBar : SearchBar
|
|
||||||
{
|
|
||||||
public ExtendedSearchBar()
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
if (ThemeManager.UsingLightTheme)
|
|
||||||
{
|
|
||||||
TextColor = Color.Black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedStackLayout : StackLayout
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Controls.IconLabelButton"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
x:Name="_iconLabelButton"
|
|
||||||
HeightRequest="45"
|
|
||||||
Padding="1"
|
|
||||||
StyleClass="btn-icon-secondary"
|
|
||||||
BackgroundColor="{Binding IconLabelBorderColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
BorderColor="Transparent"
|
|
||||||
HasShadow="False">
|
|
||||||
<Frame.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Command="{Binding ButtonCommand, Source={x:Reference _iconLabelButton}}" />
|
|
||||||
</Frame.GestureRecognizers>
|
|
||||||
<Frame
|
|
||||||
Margin="0"
|
|
||||||
Padding="0"
|
|
||||||
CornerRadius="{Binding CornerRadius, Source={x:Reference _iconLabelButton}}"
|
|
||||||
BackgroundColor="{Binding IconLabelBackgroundColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
BorderColor="Transparent"
|
|
||||||
IsClippedToBounds="True"
|
|
||||||
HasShadow="False">
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
HorizontalOptions="Center">
|
|
||||||
<controls:IconLabel
|
|
||||||
VerticalOptions="Center"
|
|
||||||
HorizontalTextAlignment="Center"
|
|
||||||
FontSize="Large"
|
|
||||||
TextColor="{Binding IconLabelColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
Text="{Binding Icon, Source={x:Reference _iconLabelButton}}">
|
|
||||||
</controls:IconLabel>
|
|
||||||
<Label
|
|
||||||
VerticalOptions="Center"
|
|
||||||
HorizontalTextAlignment="Center"
|
|
||||||
TextColor="{Binding IconLabelColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
FontSize="Medium"
|
|
||||||
Text="{Binding Label, Source={x:Reference _iconLabelButton}}"/>
|
|
||||||
</StackLayout>
|
|
||||||
</Frame>
|
|
||||||
</Frame>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class MonoEntry : Entry
|
|
||||||
{
|
|
||||||
public MonoEntry()
|
|
||||||
{
|
|
||||||
switch (Device.RuntimePlatform)
|
|
||||||
{
|
|
||||||
case Device.iOS:
|
|
||||||
FontFamily = "Menlo-Regular";
|
|
||||||
break;
|
|
||||||
case Device.Android:
|
|
||||||
FontFamily = "RobotoMono_Regular.ttf#Roboto Mono";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class MonoLabel : Label
|
|
||||||
{
|
|
||||||
public MonoLabel()
|
|
||||||
{
|
|
||||||
switch (Device.RuntimePlatform)
|
|
||||||
{
|
|
||||||
case Device.iOS:
|
|
||||||
FontFamily = "Menlo-Regular";
|
|
||||||
break;
|
|
||||||
case Device.Android:
|
|
||||||
FontFamily = "RobotoMono_Regular.ttf#Roboto Mono";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public partial class SendViewCell : ExtendedGrid
|
|
||||||
{
|
|
||||||
public static readonly BindableProperty SendProperty = BindableProperty.Create(
|
|
||||||
nameof(Send), typeof(SendView), typeof(SendViewCell), default(SendView), BindingMode.OneWay);
|
|
||||||
|
|
||||||
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
|
|
||||||
nameof(ButtonCommand), typeof(Command<SendView>), typeof(SendViewCell));
|
|
||||||
|
|
||||||
public static readonly BindableProperty ShowOptionsProperty = BindableProperty.Create(
|
|
||||||
nameof(ShowOptions), typeof(bool), typeof(SendViewCell), true, BindingMode.OneWay);
|
|
||||||
|
|
||||||
public SendViewCell()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_iconColumn.Width = new GridLength(40 * deviceActionService.GetSystemFontSizeScale(), GridUnitType.Absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SendView Send
|
|
||||||
{
|
|
||||||
get => GetValue(SendProperty) as SendView;
|
|
||||||
set => SetValue(SendProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Command<SendView> ButtonCommand
|
|
||||||
{
|
|
||||||
get => GetValue(ButtonCommandProperty) as Command<SendView>;
|
|
||||||
set => SetValue(ButtonCommandProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowOptions
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(ShowOptionsProperty);
|
|
||||||
set => SetValue(ShowOptionsProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPropertyChanged(string propertyName = null)
|
|
||||||
{
|
|
||||||
base.OnPropertyChanged(propertyName);
|
|
||||||
if (propertyName == SendProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Send == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BindingContext = new SendViewCellViewModel(Send, ShowOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoreButton_Clicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var send = ((sender as MiButton)?.BindingContext as SendViewCellViewModel)?.Send;
|
|
||||||
if (send != null)
|
|
||||||
{
|
|
||||||
ButtonCommand?.Execute(send);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class FabShadowEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public FabShadowEffect()
|
|
||||||
: base("Bitwarden.FabShadowEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class FixedSizeEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public FixedSizeEffect()
|
|
||||||
: base("Bitwarden.FixedSizeEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class NoEmojiKeyboardEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public NoEmojiKeyboardEffect()
|
|
||||||
: base("Bitwarden.NoEmojiKeyboardEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class RemoveFontPaddingEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public RemoveFontPaddingEffect()
|
|
||||||
: base("Bitwarden.RemoveFontPaddingEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public enum ScrollContentInsetAdjustmentBehavior
|
|
||||||
{
|
|
||||||
Automatic,
|
|
||||||
ScrollableAxes,
|
|
||||||
Never,
|
|
||||||
Always
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ScrollViewContentInsetAdjustmentBehaviorEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public static readonly BindableProperty ContentInsetAdjustmentBehaviorProperty =
|
|
||||||
BindableProperty.CreateAttached("ContentInsetAdjustmentBehavior", typeof(ScrollContentInsetAdjustmentBehavior), typeof(ScrollViewContentInsetAdjustmentBehaviorEffect), ScrollContentInsetAdjustmentBehavior.Automatic);
|
|
||||||
|
|
||||||
public static ScrollContentInsetAdjustmentBehavior GetContentInsetAdjustmentBehavior(BindableObject view)
|
|
||||||
{
|
|
||||||
return (ScrollContentInsetAdjustmentBehavior)view.GetValue(ContentInsetAdjustmentBehaviorProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetContentInsetAdjustmentBehavior(BindableObject view, ScrollContentInsetAdjustmentBehavior value)
|
|
||||||
{
|
|
||||||
view.SetValue(ContentInsetAdjustmentBehaviorProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScrollViewContentInsetAdjustmentBehaviorEffect()
|
|
||||||
: base($"Bitwarden.{nameof(ScrollViewContentInsetAdjustmentBehaviorEffect)}")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class TabBarEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public TabBarEffect()
|
|
||||||
: base("Bitwarden.TabBarEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
src/App/Handlers/HybridWebViewHandler.cs
Normal file
25
src/App/Handlers/HybridWebViewHandler.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#if IOS || MACCATALYST
|
||||||
|
using PlatformView = WebKit.WKWebView;
|
||||||
|
#elif ANDROID
|
||||||
|
using PlatformView = Android.Webkit.WebView;
|
||||||
|
#elif (NETSTANDARD || !PLATFORM) || (NET6_0_OR_GREATER && !IOS && !ANDROID)
|
||||||
|
using PlatformView = System.Object;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using Bit.App.Controls;
|
||||||
|
using Microsoft.Maui.Handlers;
|
||||||
|
|
||||||
|
namespace Bit.App.Handlers
|
||||||
|
{
|
||||||
|
public partial class HybridWebViewHandler
|
||||||
|
{
|
||||||
|
public static PropertyMapper<HybridWebView, HybridWebViewHandler> PropertyMapper = new PropertyMapper<HybridWebView, HybridWebViewHandler>(ViewHandler.ViewMapper)
|
||||||
|
{
|
||||||
|
[nameof(HybridWebView.Uri)] = MapUri
|
||||||
|
};
|
||||||
|
|
||||||
|
public HybridWebViewHandler() : base(PropertyMapper)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/App/MauiProgram.cs
Normal file
41
src/App/MauiProgram.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
namespace Bit.App
|
||||||
|
{
|
||||||
|
public class MauiProgram
|
||||||
|
{
|
||||||
|
public static MauiApp CreateMauiApp()
|
||||||
|
{
|
||||||
|
return Core.MauiProgram.ConfigureMauiAppBuilder(
|
||||||
|
effects =>
|
||||||
|
{
|
||||||
|
#if IOS
|
||||||
|
iOS.Core.Utilities.iOSCoreHelpers.ConfigureMAUIEffects(effects);
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
handlers =>
|
||||||
|
{
|
||||||
|
handlers.AddHandler(typeof(Bit.App.Controls.HybridWebView), typeof(Bit.App.Handlers.HybridWebViewHandler));
|
||||||
|
#if ANDROID
|
||||||
|
Bit.App.Handlers.EntryHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.EditorHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.LabelHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.PickerHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.SearchBarHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.SwitchHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.DatePickerHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.SliderHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.StepperHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.TimePickerHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.ButtonHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.ToolbarHandlerMappings.Setup();
|
||||||
|
|
||||||
|
handlers.AddHandler(typeof(Bit.App.Pages.TabsPage), typeof(Bit.App.Handlers.CustomTabbedPageHandler));
|
||||||
|
handlers.AddHandler(typeof(Bit.App.Controls.ExtendedDatePicker), typeof(Bit.App.Handlers.ExtendedDatePickerHandler));
|
||||||
|
#else
|
||||||
|
iOS.Core.Utilities.iOSCoreHelpers.ConfigureMAUIHandlers(handlers);
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
initUseMauiApp: true
|
||||||
|
).Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.HomePage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:HomeViewModel"
|
|
||||||
x:Name="_page"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:HomeViewModel />
|
|
||||||
</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}" />
|
|
||||||
<ToolbarItem x:Name="_closeButton" Text="{u:I18n Close}" Command="{Binding CloseCommand}" Order="Primary" Priority="-1"/>
|
|
||||||
</ContentPage.ToolbarItems>
|
|
||||||
|
|
||||||
<ContentPage.Resources>
|
|
||||||
<ResourceDictionary>
|
|
||||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
|
||||||
<StackLayout x:Name="_mainLayout" x:Key="mainLayout" Spacing="30" Padding="20, 50, 20, 0">
|
|
||||||
<Image
|
|
||||||
x:Name="_logo"
|
|
||||||
Source="logo.png"
|
|
||||||
VerticalOptions="Center" />
|
|
||||||
<Label Text="{u:I18n LoginOrCreateNewAccount}"
|
|
||||||
StyleClass="text-lg"
|
|
||||||
HorizontalTextAlignment="Center"/>
|
|
||||||
<StackLayout
|
|
||||||
StyleClass="box-row">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n EmailAddress}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Entry
|
|
||||||
x:Name="_email"
|
|
||||||
Text="{Binding Email}"
|
|
||||||
Keyboard="Email"
|
|
||||||
StyleClass="box-value"
|
|
||||||
ReturnType="Go"
|
|
||||||
ReturnCommand="{Binding ContinueCommand}">
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{DynamicResource MutedColor}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Entry>
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
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"/>
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Margin="0, 20, 0 ,0">
|
|
||||||
<StackLayout.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer
|
|
||||||
Command="{Binding RememberEmailCommand}" />
|
|
||||||
</StackLayout.GestureRecognizers>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n RememberMe}"
|
|
||||||
StyleClass="text-sm"
|
|
||||||
HorizontalOptions="FillAndExpand"
|
|
||||||
VerticalOptions="Center"
|
|
||||||
VerticalTextAlignment="Center"/>
|
|
||||||
<Switch
|
|
||||||
Scale="0.8"
|
|
||||||
IsToggled="{Binding RememberEmail}"
|
|
||||||
VerticalOptions="Center"/>
|
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<Button Text="{u:I18n Continue}"
|
|
||||||
StyleClass="btn-primary"
|
|
||||||
IsEnabled="{Binding CanContinue}"
|
|
||||||
Command="{Binding ContinueCommand}" />
|
|
||||||
|
|
||||||
<Label FormattedText="{Binding CreateAccountText}"
|
|
||||||
Margin="0, 10"
|
|
||||||
StyleClass="box-footer-label">
|
|
||||||
<Label.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Command="{Binding CreateAccountCommand}" />
|
|
||||||
</Label.GestureRecognizers>
|
|
||||||
</Label>
|
|
||||||
</StackLayout>
|
|
||||||
</ResourceDictionary>
|
|
||||||
</ContentPage.Resources>
|
|
||||||
|
|
||||||
<AbsoluteLayout
|
|
||||||
x:Name="_absLayout"
|
|
||||||
VerticalOptions="FillAndExpand"
|
|
||||||
HorizontalOptions="FillAndExpand">
|
|
||||||
<ContentView
|
|
||||||
x:Name="_mainContent"
|
|
||||||
AbsoluteLayout.LayoutFlags="All"
|
|
||||||
AbsoluteLayout.LayoutBounds="0, 0, 1, 1">
|
|
||||||
</ContentView>
|
|
||||||
|
|
||||||
<controls:AccountSwitchingOverlayView
|
|
||||||
x:Name="_accountListOverlay"
|
|
||||||
AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
|
|
||||||
AbsoluteLayout.LayoutFlags="All"
|
|
||||||
MainPage="{Binding Source={x:Reference _page}}"
|
|
||||||
BindingContext="{Binding AccountSwitchingOverlayViewModel}"/>
|
|
||||||
</AbsoluteLayout>
|
|
||||||
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,468 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
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.Enums;
|
|
||||||
using Bit.Core.Models.Domain;
|
|
||||||
using Bit.Core.Models.Request;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.CommunityToolkit.Helpers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class LockPageViewModel : BaseViewModel
|
|
||||||
{
|
|
||||||
private readonly IApiService _apiService;
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
|
||||||
private readonly ICryptoService _cryptoService;
|
|
||||||
private readonly IMessagingService _messagingService;
|
|
||||||
private readonly IEnvironmentService _environmentService;
|
|
||||||
private readonly IStateService _stateService;
|
|
||||||
private readonly IBiometricService _biometricService;
|
|
||||||
private readonly IKeyConnectorService _keyConnectorService;
|
|
||||||
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;
|
|
||||||
private string _pin;
|
|
||||||
private bool _showPassword;
|
|
||||||
private bool _pinLock;
|
|
||||||
private bool _biometricLock;
|
|
||||||
private bool _biometricIntegrityValid = true;
|
|
||||||
private bool _biometricButtonVisible;
|
|
||||||
private bool _usingKeyConnector;
|
|
||||||
private string _biometricButtonText;
|
|
||||||
private string _loggedInAsText;
|
|
||||||
private string _lockedVerifyText;
|
|
||||||
private bool _isPinProtected;
|
|
||||||
private bool _isPinProtectedWithKey;
|
|
||||||
|
|
||||||
public LockPageViewModel()
|
|
||||||
{
|
|
||||||
_apiService = ServiceContainer.Resolve<IApiService>("apiService");
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
|
||||||
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
|
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
|
||||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
|
|
||||||
_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);
|
|
||||||
SubmitCommand = new Command(async () => await SubmitAsync());
|
|
||||||
|
|
||||||
AccountSwitchingOverlayViewModel = new AccountSwitchingOverlayViewModel(_stateService, _messagingService, _logger)
|
|
||||||
{
|
|
||||||
AllowAddAccountRow = true,
|
|
||||||
AllowActiveAccountSelection = true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public string MasterPassword
|
|
||||||
{
|
|
||||||
get => _masterPassword;
|
|
||||||
set => SetProperty(ref _masterPassword, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Pin
|
|
||||||
{
|
|
||||||
get => _pin;
|
|
||||||
set => SetProperty(ref _pin, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowPassword
|
|
||||||
{
|
|
||||||
get => _showPassword;
|
|
||||||
set => SetProperty(ref _showPassword, value,
|
|
||||||
additionalPropertyNames: new string[]
|
|
||||||
{
|
|
||||||
nameof(ShowPasswordIcon),
|
|
||||||
nameof(PasswordVisibilityAccessibilityText),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PinLock
|
|
||||||
{
|
|
||||||
get => _pinLock;
|
|
||||||
set => SetProperty(ref _pinLock, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool UsingKeyConnector
|
|
||||||
{
|
|
||||||
get => _usingKeyConnector;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BiometricLock
|
|
||||||
{
|
|
||||||
get => _biometricLock;
|
|
||||||
set => SetProperty(ref _biometricLock, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BiometricIntegrityValid
|
|
||||||
{
|
|
||||||
get => _biometricIntegrityValid;
|
|
||||||
set => SetProperty(ref _biometricIntegrityValid, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool BiometricButtonVisible
|
|
||||||
{
|
|
||||||
get => _biometricButtonVisible;
|
|
||||||
set => SetProperty(ref _biometricButtonVisible, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string BiometricButtonText
|
|
||||||
{
|
|
||||||
get => _biometricButtonText;
|
|
||||||
set => SetProperty(ref _biometricButtonText, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string LoggedInAsText
|
|
||||||
{
|
|
||||||
get => _loggedInAsText;
|
|
||||||
set => SetProperty(ref _loggedInAsText, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string LockedVerifyText
|
|
||||||
{
|
|
||||||
get => _lockedVerifyText;
|
|
||||||
set => SetProperty(ref _lockedVerifyText, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; }
|
|
||||||
|
|
||||||
public Command SubmitCommand { get; }
|
|
||||||
public Command TogglePasswordCommand { get; }
|
|
||||||
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
|
|
||||||
public string PasswordVisibilityAccessibilityText => ShowPassword ? AppResources.PasswordIsVisibleTapToHide : AppResources.PasswordIsNotVisibleTapToShow;
|
|
||||||
public Action UnlockedAction { get; set; }
|
|
||||||
public event Action<int?> FocusSecretEntry
|
|
||||||
{
|
|
||||||
add => _secretEntryFocusWeakEventManager.AddEventHandler(value);
|
|
||||||
remove => _secretEntryFocusWeakEventManager.RemoveEventHandler(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InitAsync()
|
|
||||||
{
|
|
||||||
(_isPinProtected, _isPinProtectedWithKey) = await _vaultTimeoutService.IsPinLockSetAsync();
|
|
||||||
PinLock = (_isPinProtected && await _stateService.GetPinProtectedKeyAsync() != null) ||
|
|
||||||
_isPinProtectedWithKey;
|
|
||||||
BiometricLock = await _vaultTimeoutService.IsBiometricLockSetAsync() && await _cryptoService.HasKeyAsync();
|
|
||||||
|
|
||||||
// Users with key connector and without biometric or pin has no MP to unlock with
|
|
||||||
_usingKeyConnector = await _keyConnectorService.GetUsesKeyConnector();
|
|
||||||
if (_usingKeyConnector && !(BiometricLock || PinLock))
|
|
||||||
{
|
|
||||||
await _vaultTimeoutService.LogOutAsync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_email = await _stateService.GetEmailAsync();
|
|
||||||
if (string.IsNullOrWhiteSpace(_email))
|
|
||||||
{
|
|
||||||
await _vaultTimeoutService.LogOutAsync();
|
|
||||||
_logger.Exception(new NullReferenceException("Email not found in storage"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var webVault = _environmentService.GetWebVaultUrl(true);
|
|
||||||
if (string.IsNullOrWhiteSpace(webVault))
|
|
||||||
{
|
|
||||||
webVault = "https://bitwarden.com";
|
|
||||||
}
|
|
||||||
var webVaultHostname = CoreHelpers.GetHostname(webVault);
|
|
||||||
LoggedInAsText = string.Format(AppResources.LoggedInAsOn, _email, webVaultHostname);
|
|
||||||
if (PinLock)
|
|
||||||
{
|
|
||||||
PageTitle = AppResources.VerifyPIN;
|
|
||||||
LockedVerifyText = AppResources.VaultLockedPIN;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_usingKeyConnector)
|
|
||||||
{
|
|
||||||
PageTitle = AppResources.UnlockVault;
|
|
||||||
LockedVerifyText = AppResources.VaultLockedIdentity;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PageTitle = AppResources.VerifyMasterPassword;
|
|
||||||
LockedVerifyText = AppResources.VaultLockedMasterPassword;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BiometricLock)
|
|
||||||
{
|
|
||||||
BiometricIntegrityValid = await _platformUtilsService.IsBiometricIntegrityValidAsync();
|
|
||||||
if (!_biometricIntegrityValid)
|
|
||||||
{
|
|
||||||
BiometricButtonVisible = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BiometricButtonVisible = true;
|
|
||||||
BiometricButtonText = AppResources.UseBiometricsToUnlock;
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
var supportsFace = await _deviceActionService.SupportsFaceBiometricAsync();
|
|
||||||
BiometricButtonText = supportsFace ? AppResources.UseFaceIDToUnlock :
|
|
||||||
AppResources.UseFingerprintToUnlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SubmitAsync()
|
|
||||||
{
|
|
||||||
if (PinLock && string.IsNullOrWhiteSpace(Pin))
|
|
||||||
{
|
|
||||||
await Page.DisplayAlert(AppResources.AnErrorHasOccurred,
|
|
||||||
string.Format(AppResources.ValidationFieldRequired, AppResources.PIN),
|
|
||||||
AppResources.Ok);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!PinLock && string.IsNullOrWhiteSpace(MasterPassword))
|
|
||||||
{
|
|
||||||
await Page.DisplayAlert(AppResources.AnErrorHasOccurred,
|
|
||||||
string.Format(AppResources.ValidationFieldRequired, AppResources.MasterPassword),
|
|
||||||
AppResources.Ok);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShowPassword = false;
|
|
||||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
|
||||||
|
|
||||||
if (PinLock)
|
|
||||||
{
|
|
||||||
var failed = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_isPinProtected)
|
|
||||||
{
|
|
||||||
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email,
|
|
||||||
kdfConfig,
|
|
||||||
await _stateService.GetPinProtectedKeyAsync());
|
|
||||||
var encKey = await _cryptoService.GetEncKeyAsync(key);
|
|
||||||
var protectedPin = await _stateService.GetProtectedPinAsync();
|
|
||||||
var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey);
|
|
||||||
failed = decPin != Pin;
|
|
||||||
if (!failed)
|
|
||||||
{
|
|
||||||
Pin = string.Empty;
|
|
||||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
|
||||||
await SetKeyAndContinueAsync(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var key = await _cryptoService.MakeKeyFromPinAsync(Pin, _email, kdfConfig);
|
|
||||||
failed = false;
|
|
||||||
Pin = string.Empty;
|
|
||||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
|
||||||
await SetKeyAndContinueAsync(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
failed = true;
|
|
||||||
}
|
|
||||||
if (failed)
|
|
||||||
{
|
|
||||||
var invalidUnlockAttempts = await AppHelpers.IncrementInvalidUnlockAttemptsAsync();
|
|
||||||
if (invalidUnlockAttempts >= 5)
|
|
||||||
{
|
|
||||||
_messagingService.Send("logout");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.InvalidPIN,
|
|
||||||
AppResources.AnErrorHasOccurred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdfConfig);
|
|
||||||
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
|
|
||||||
var passwordValid = false;
|
|
||||||
MasterPasswordPolicyOptions enforcedMasterPasswordOptions = null;
|
|
||||||
|
|
||||||
if (storedKeyHash != null)
|
|
||||||
{
|
|
||||||
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
|
|
||||||
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
|
|
||||||
var request = new PasswordVerificationRequest();
|
|
||||||
request.MasterPasswordHash = keyHash;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await _apiService.PostAccountVerifyPasswordAsync(request);
|
|
||||||
enforcedMasterPasswordOptions = response.MasterPasswordPolicy;
|
|
||||||
passwordValid = true;
|
|
||||||
var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization);
|
|
||||||
await _cryptoService.SetKeyHashAsync(localKeyHash);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", e.GetType(), e.StackTrace);
|
|
||||||
}
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
}
|
|
||||||
if (passwordValid)
|
|
||||||
{
|
|
||||||
if (_isPinProtected)
|
|
||||||
{
|
|
||||||
var protectedPin = await _stateService.GetProtectedPinAsync();
|
|
||||||
var encKey = await _cryptoService.GetEncKeyAsync(key);
|
|
||||||
var decPin = await _cryptoService.DecryptToUtf8Async(new EncString(protectedPin), encKey);
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Re-enable biometrics
|
|
||||||
if (BiometricLock & !BiometricIntegrityValid)
|
|
||||||
{
|
|
||||||
await _biometricService.SetupBiometricAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var invalidUnlockAttempts = await AppHelpers.IncrementInvalidUnlockAttemptsAsync();
|
|
||||||
if (invalidUnlockAttempts >= 5)
|
|
||||||
{
|
|
||||||
_messagingService.Send("logout");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.InvalidMasterPassword,
|
|
||||||
AppResources.AnErrorHasOccurred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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,
|
|
||||||
AppResources.LogOut, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (confirmed)
|
|
||||||
{
|
|
||||||
_messagingService.Send("logout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetPinPasswordFields()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MasterPassword = string.Empty;
|
|
||||||
Pin = string.Empty;
|
|
||||||
ShowPassword = false;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TogglePassword()
|
|
||||||
{
|
|
||||||
ShowPassword = !ShowPassword;
|
|
||||||
var secret = PinLock ? Pin : MasterPassword;
|
|
||||||
_secretEntryFocusWeakEventManager.RaiseEvent(string.IsNullOrEmpty(secret) ? 0 : secret.Length, nameof(FocusSecretEntry));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task PromptBiometricAsync()
|
|
||||||
{
|
|
||||||
BiometricIntegrityValid = await _platformUtilsService.IsBiometricIntegrityValidAsync();
|
|
||||||
BiometricButtonVisible = BiometricIntegrityValid;
|
|
||||||
if (!BiometricLock || !BiometricIntegrityValid)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var success = await _platformUtilsService.AuthenticateBiometricAsync(null,
|
|
||||||
PinLock ? AppResources.PIN : AppResources.MasterPassword,
|
|
||||||
() => _secretEntryFocusWeakEventManager.RaiseEvent((int?)null, nameof(FocusSecretEntry)));
|
|
||||||
await _stateService.SetBiometricLockedAsync(!success);
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
await DoContinueAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetKeyAndContinueAsync(SymmetricCryptoKey key)
|
|
||||||
{
|
|
||||||
var hasKey = await _cryptoService.HasKeyAsync();
|
|
||||||
if (!hasKey)
|
|
||||||
{
|
|
||||||
await _cryptoService.SetKeyAsync(key);
|
|
||||||
}
|
|
||||||
await DoContinueAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DoContinueAsync()
|
|
||||||
{
|
|
||||||
await _stateService.SetBiometricLockedAsync(false);
|
|
||||||
_watchDeviceService.SyncDataToWatchAsync().FireAndForget();
|
|
||||||
_messagingService.Send("unlocked");
|
|
||||||
UnlockedAction?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.LoginPasswordlessRequestPage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:LoginPasswordlessRequestViewModel"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:LoginPasswordlessRequestViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ContentPage.ToolbarItems>
|
|
||||||
<ToolbarItem Text="{u:I18n Close}" Command="{Binding CloseCommand}" Order="Primary" Priority="-1" x:Name="_closeItem"/>
|
|
||||||
</ContentPage.ToolbarItems>
|
|
||||||
|
|
||||||
<ScrollView>
|
|
||||||
<StackLayout
|
|
||||||
Padding="7, 0, 7, 20">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n LogInInitiated}"
|
|
||||||
FontSize="Title"
|
|
||||||
FontAttributes="Bold"
|
|
||||||
Margin="0,14,0,21"/>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ANotificationHasBeenSentToYourDevice}"
|
|
||||||
FontSize="Small"
|
|
||||||
Margin="0,0,0,10"/>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n PleaseMakeSureYourVaultIsUnlockedAndTheFingerprintPhraseMatchesOnTheOtherDevice}"
|
|
||||||
FontSize="Small"
|
|
||||||
Margin="0,0,0,24"/>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n FingerprintPhrase}"
|
|
||||||
FontSize="Small"
|
|
||||||
FontAttributes="Bold"/>
|
|
||||||
<controls:MonoLabel
|
|
||||||
FormattedText="{Binding FingerprintPhrase}"
|
|
||||||
FontSize="Medium"
|
|
||||||
TextColor="{DynamicResource FingerprintPhrase}"/>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ResendNotification}"
|
|
||||||
StyleClass="text-md"
|
|
||||||
HorizontalOptions="Start"
|
|
||||||
Margin="0,40,0,0"
|
|
||||||
TextColor="{DynamicResource HyperlinkColor}">
|
|
||||||
<Label.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Command="{Binding CreatePasswordlessLoginCommand}" />
|
|
||||||
</Label.GestureRecognizers>
|
|
||||||
</Label>
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Margin="0,30,0,0">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n NeedAnotherOption}"
|
|
||||||
FontSize="Small"
|
|
||||||
VerticalTextAlignment="End"/>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ViewAllLoginOptions}"
|
|
||||||
StyleClass="text-md"
|
|
||||||
VerticalTextAlignment="End"
|
|
||||||
VerticalOptions="CenterAndExpand"
|
|
||||||
Margin="5, 0"
|
|
||||||
TextColor="{DynamicResource HyperlinkColor}">
|
|
||||||
<Label.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Command="{Binding CloseCommand}" />
|
|
||||||
</Label.GestureRecognizers>
|
|
||||||
</Label>
|
|
||||||
</StackLayout>
|
|
||||||
|
|
||||||
</StackLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Models.Domain;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.CommunityToolkit.ObjectModel;
|
|
||||||
using Xamarin.Essentials;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class LoginPasswordlessRequestViewModel : CaptchaProtectedViewModel
|
|
||||||
{
|
|
||||||
private const int REQUEST_TIME_UPDATE_PERIOD_IN_SECONDS = 4;
|
|
||||||
|
|
||||||
private IDeviceActionService _deviceActionService;
|
|
||||||
private IAuthService _authService;
|
|
||||||
private ISyncService _syncService;
|
|
||||||
private II18nService _i18nService;
|
|
||||||
private IStateService _stateService;
|
|
||||||
private IPlatformUtilsService _platformUtilsService;
|
|
||||||
private IEnvironmentService _environmentService;
|
|
||||||
private ILogger _logger;
|
|
||||||
|
|
||||||
protected override II18nService i18nService => _i18nService;
|
|
||||||
protected override IEnvironmentService environmentService => _environmentService;
|
|
||||||
protected override IDeviceActionService deviceActionService => _deviceActionService;
|
|
||||||
protected override IPlatformUtilsService platformUtilsService => _platformUtilsService;
|
|
||||||
|
|
||||||
private CancellationTokenSource _checkLoginRequestStatusCts;
|
|
||||||
private Task _checkLoginRequestStatusTask;
|
|
||||||
private string _fingerprintPhrase;
|
|
||||||
private string _email;
|
|
||||||
private string _requestId;
|
|
||||||
private string _requestAccessCode;
|
|
||||||
// Item1 publicKey, Item2 privateKey
|
|
||||||
private Tuple<byte[], byte[]> _requestKeyPair;
|
|
||||||
|
|
||||||
public LoginPasswordlessRequestViewModel()
|
|
||||||
{
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>();
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
|
|
||||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>();
|
|
||||||
_authService = ServiceContainer.Resolve<IAuthService>();
|
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>();
|
|
||||||
_i18nService = ServiceContainer.Resolve<II18nService>();
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>();
|
|
||||||
_logger = ServiceContainer.Resolve<ILogger>();
|
|
||||||
|
|
||||||
PageTitle = AppResources.LogInWithAnotherDevice;
|
|
||||||
|
|
||||||
CreatePasswordlessLoginCommand = new AsyncCommand(CreatePasswordlessLoginAsync,
|
|
||||||
onException: ex => HandleException(ex),
|
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
|
|
||||||
CloseCommand = new AsyncCommand(() => Device.InvokeOnMainThreadAsync(CloseAction),
|
|
||||||
onException: _logger.Exception,
|
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Action StartTwoFactorAction { get; set; }
|
|
||||||
public Action LogInSuccessAction { get; set; }
|
|
||||||
public Action UpdateTempPasswordAction { get; set; }
|
|
||||||
public Action CloseAction { get; set; }
|
|
||||||
|
|
||||||
public ICommand CreatePasswordlessLoginCommand { get; }
|
|
||||||
public ICommand CloseCommand { get; }
|
|
||||||
|
|
||||||
public string FingerprintPhrase
|
|
||||||
{
|
|
||||||
get => _fingerprintPhrase;
|
|
||||||
set => SetProperty(ref _fingerprintPhrase, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Email
|
|
||||||
{
|
|
||||||
get => _email;
|
|
||||||
set => SetProperty(ref _email, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartCheckLoginRequestStatus()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_checkLoginRequestStatusCts?.Cancel();
|
|
||||||
_checkLoginRequestStatusCts = new CancellationTokenSource();
|
|
||||||
_checkLoginRequestStatusTask = new TimerTask(_logger, CheckLoginRequestStatus, _checkLoginRequestStatusCts).RunPeriodic(TimeSpan.FromSeconds(REQUEST_TIME_UPDATE_PERIOD_IN_SECONDS));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Exception(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopCheckLoginRequestStatus()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_checkLoginRequestStatusCts?.Cancel();
|
|
||||||
_checkLoginRequestStatusCts?.Dispose();
|
|
||||||
_checkLoginRequestStatusCts = null;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_logger.Exception(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CheckLoginRequestStatus()
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_requestId) || string.IsNullOrEmpty(_requestAccessCode))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var response = await _authService.GetPasswordlessLoginResponseAsync(_requestId, _requestAccessCode);
|
|
||||||
|
|
||||||
if (response.RequestApproved == null || !response.RequestApproved.Value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
StopCheckLoginRequestStatus();
|
|
||||||
|
|
||||||
var authResult = await _authService.LogInPasswordlessAsync(Email, _requestAccessCode, _requestId, _requestKeyPair.Item2, response.Key, response.MasterPasswordHash);
|
|
||||||
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
|
|
||||||
|
|
||||||
if (await HandleCaptchaAsync(authResult.CaptchaSiteKey, authResult.CaptchaNeeded, CheckLoginRequestStatus))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (authResult.TwoFactor)
|
|
||||||
{
|
|
||||||
StartTwoFactorAction?.Invoke();
|
|
||||||
}
|
|
||||||
else if (authResult.ForcePasswordReset)
|
|
||||||
{
|
|
||||||
UpdateTempPasswordAction?.Invoke();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_syncService.FullSyncAsync(true).FireAndForget();
|
|
||||||
LogInSuccessAction?.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
StartCheckLoginRequestStatus();
|
|
||||||
HandleException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CreatePasswordlessLoginAsync()
|
|
||||||
{
|
|
||||||
await Device.InvokeOnMainThreadAsync(() => _deviceActionService.ShowLoadingAsync(AppResources.Loading));
|
|
||||||
|
|
||||||
var response = await _authService.PasswordlessCreateLoginRequestAsync(_email);
|
|
||||||
if (response != null)
|
|
||||||
{
|
|
||||||
FingerprintPhrase = response.FingerprintPhrase;
|
|
||||||
_requestId = response.Id;
|
|
||||||
_requestAccessCode = response.RequestAccessCode;
|
|
||||||
_requestKeyPair = response.RequestKeyPair;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleException(Exception ex)
|
|
||||||
{
|
|
||||||
Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync(async () =>
|
|
||||||
{
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.GenericErrorMessage);
|
|
||||||
}).FireAndForget();
|
|
||||||
_logger.Exception(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Exceptions;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public abstract class BaseViewModel : ExtendedViewModel
|
|
||||||
{
|
|
||||||
private string _pageTitle = string.Empty;
|
|
||||||
private AvatarImageSource _avatar;
|
|
||||||
private LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
|
||||||
private LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
|
|
||||||
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
|
||||||
|
|
||||||
public string PageTitle
|
|
||||||
{
|
|
||||||
get => _pageTitle;
|
|
||||||
set => SetProperty(ref _pageTitle, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvatarImageSource AvatarImageSource
|
|
||||||
{
|
|
||||||
get => _avatar ?? new AvatarImageSource();
|
|
||||||
set => SetProperty(ref _avatar, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContentPage Page { get; set; }
|
|
||||||
|
|
||||||
protected void HandleException(Exception ex, string message = null)
|
|
||||||
{
|
|
||||||
if (ex is ApiException apiException && apiException.Error != null)
|
|
||||||
{
|
|
||||||
message = apiException.Error.GetSingleMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync(async () =>
|
|
||||||
{
|
|
||||||
await _deviceActionService.Value.HideLoadingAsync();
|
|
||||||
await _platformUtilsService.Value.ShowDialogAsync(message ?? AppResources.GenericErrorMessage);
|
|
||||||
}).FireAndForget();
|
|
||||||
_logger.Value.Exception(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SendGroupingsPageListItem : ISendGroupingsPageListItem
|
|
||||||
{
|
|
||||||
private string _icon;
|
|
||||||
private string _name;
|
|
||||||
|
|
||||||
public SendView Send { get; set; }
|
|
||||||
public SendType? Type { get; set; }
|
|
||||||
public string ItemCount { get; set; }
|
|
||||||
public bool ShowOptions { get; set; }
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_name != null)
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
if (Type != null)
|
|
||||||
{
|
|
||||||
switch (Type.Value)
|
|
||||||
{
|
|
||||||
case SendType.Text:
|
|
||||||
_name = AppResources.TypeText;
|
|
||||||
break;
|
|
||||||
case SendType.File:
|
|
||||||
_name = AppResources.TypeFile;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Icon
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_icon != null)
|
|
||||||
{
|
|
||||||
return _icon;
|
|
||||||
}
|
|
||||||
if (Type != null)
|
|
||||||
{
|
|
||||||
switch (Type.Value)
|
|
||||||
{
|
|
||||||
case SendType.Text:
|
|
||||||
_icon = BitwardenIcons.FileText;
|
|
||||||
break;
|
|
||||||
case SendType.File:
|
|
||||||
_icon = BitwardenIcons.File;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _icon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.AutofillServicesPage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:AutofillServicesPageViewModel"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:AutofillServicesPageViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ScrollView>
|
|
||||||
<StackLayout Padding="0" Spacing="20">
|
|
||||||
<StackLayout
|
|
||||||
StyleClass="box"
|
|
||||||
IsVisible="{Binding AutofillServiceVisible}">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n AutofillService}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<RelativeLayout HorizontalOptions="End">
|
|
||||||
<Switch
|
|
||||||
x:Name="AutofillServiceSwitch"
|
|
||||||
IsToggled="{Binding AutofillServiceToggled}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
<Button
|
|
||||||
Clicked="ToggleAutofillService"
|
|
||||||
StyleClass="box-overlay"
|
|
||||||
RelativeLayout.XConstraint="0"
|
|
||||||
RelativeLayout.YConstraint="0"
|
|
||||||
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AutofillServiceSwitch, Property=Width}"
|
|
||||||
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AutofillServiceSwitch, Property=Height}" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n AutofillServiceDescription}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
StyleClass="box"
|
|
||||||
IsVisible="{Binding InlineAutofillVisible}">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n InlineAutofill}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
IsEnabled="{Binding InlineAutofillEnabled}"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<RelativeLayout HorizontalOptions="End">
|
|
||||||
<Switch
|
|
||||||
x:Name="InlineAutofillSwitch"
|
|
||||||
IsEnabled="{Binding InlineAutofillEnabled}"
|
|
||||||
IsToggled="{Binding InlineAutofillToggled}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
<Button
|
|
||||||
Clicked="ToggleInlineAutofill"
|
|
||||||
StyleClass="box-overlay"
|
|
||||||
RelativeLayout.XConstraint="0"
|
|
||||||
RelativeLayout.YConstraint="0"
|
|
||||||
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=InlineAutofillSwitch, Property=Width}"
|
|
||||||
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=InlineAutofillSwitch, Property=Height}" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n InlineAutofillDescription}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch"
|
|
||||||
IsEnabled="{Binding InlineAutofillEnabled}"/>
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n Accessibility}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<RelativeLayout HorizontalOptions="End">
|
|
||||||
<Switch
|
|
||||||
x:Name="AccessibilitySwitch"
|
|
||||||
IsToggled="{Binding AccessibilityToggled}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
<Button
|
|
||||||
Command="{Binding ToggleAccessibilityCommand}"
|
|
||||||
StyleClass="box-overlay"
|
|
||||||
RelativeLayout.XConstraint="0"
|
|
||||||
RelativeLayout.YConstraint="0"
|
|
||||||
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AccessibilitySwitch, Property=Width}"
|
|
||||||
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=AccessibilitySwitch, Property=Height}" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{Binding AccessibilityDescriptionLabel}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
StyleClass="box"
|
|
||||||
IsVisible="{Binding DrawOverVisible}">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n DrawOver}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
IsEnabled="{Binding DrawOverEnabled}"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<RelativeLayout HorizontalOptions="End">
|
|
||||||
<Switch
|
|
||||||
x:Name="DrawOverSwitch"
|
|
||||||
IsEnabled="{Binding DrawOverEnabled}"
|
|
||||||
IsToggled="{Binding DrawOverToggled}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
<Button
|
|
||||||
Clicked="ToggleDrawOver"
|
|
||||||
StyleClass="box-overlay"
|
|
||||||
RelativeLayout.XConstraint="0"
|
|
||||||
RelativeLayout.YConstraint="0"
|
|
||||||
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToView, ElementName=DrawOverSwitch, Property=Width}"
|
|
||||||
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToView, ElementName=DrawOverSwitch, Property=Height}" />
|
|
||||||
</RelativeLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{Binding DrawOverDescriptionLabel}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch"
|
|
||||||
IsEnabled="{Binding InlineAutofillEnabled}"/>
|
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public partial class AutofillServicesPage : BaseContentPage
|
|
||||||
{
|
|
||||||
private readonly AutofillServicesPageViewModel _vm;
|
|
||||||
private readonly SettingsPage _settingsPage;
|
|
||||||
private DateTime? _timerStarted = null;
|
|
||||||
private TimeSpan _timerMaxLength = TimeSpan.FromMinutes(5);
|
|
||||||
|
|
||||||
public AutofillServicesPage(SettingsPage settingsPage)
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
_vm = BindingContext as AutofillServicesPageViewModel;
|
|
||||||
_vm.Page = this;
|
|
||||||
_settingsPage = settingsPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
|
||||||
{
|
|
||||||
await _vm.InitAsync();
|
|
||||||
_vm.UpdateEnabled();
|
|
||||||
_timerStarted = DateTime.UtcNow;
|
|
||||||
Device.StartTimer(new TimeSpan(0, 0, 0, 0, 500), () =>
|
|
||||||
{
|
|
||||||
if (_timerStarted == null || (DateTime.UtcNow - _timerStarted) > _timerMaxLength)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_vm.UpdateEnabled();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
base.OnAppearing();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDisappearing()
|
|
||||||
{
|
|
||||||
_timerStarted = null;
|
|
||||||
_settingsPage.BuildList();
|
|
||||||
base.OnDisappearing();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleAutofillService(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (DoOnce())
|
|
||||||
{
|
|
||||||
_vm.ToggleAutofillService();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleInlineAutofill(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
_vm.ToggleInlineAutofill();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleDrawOver(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (DoOnce())
|
|
||||||
{
|
|
||||||
_vm.ToggleDrawOver();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,231 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.App.Services;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.CommunityToolkit.ObjectModel;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class AutofillServicesPageViewModel : BaseViewModel
|
|
||||||
{
|
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly IAutofillHandler _autofillHandler;
|
|
||||||
private readonly IStateService _stateService;
|
|
||||||
private readonly MobileI18nService _i18nService;
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
|
||||||
|
|
||||||
private bool _autofillServiceToggled;
|
|
||||||
private bool _inlineAutofillToggled;
|
|
||||||
private bool _accessibilityToggled;
|
|
||||||
private bool _drawOverToggled;
|
|
||||||
private bool _inited;
|
|
||||||
|
|
||||||
public AutofillServicesPageViewModel()
|
|
||||||
{
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
PageTitle = AppResources.AutofillServices;
|
|
||||||
ToggleAccessibilityCommand = new AsyncCommand(ToggleAccessibilityAsync,
|
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Autofill Service
|
|
||||||
|
|
||||||
public bool AutofillServiceVisible
|
|
||||||
{
|
|
||||||
get => _deviceActionService.SystemMajorVersion() >= 26;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AutofillServiceToggled
|
|
||||||
{
|
|
||||||
get => _autofillServiceToggled;
|
|
||||||
set => SetProperty(ref _autofillServiceToggled, value,
|
|
||||||
additionalPropertyNames: new string[]
|
|
||||||
{
|
|
||||||
nameof(InlineAutofillEnabled)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Inline Autofill
|
|
||||||
|
|
||||||
public bool InlineAutofillVisible
|
|
||||||
{
|
|
||||||
get => _deviceActionService.SystemMajorVersion() >= 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool InlineAutofillEnabled
|
|
||||||
{
|
|
||||||
get => AutofillServiceToggled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool InlineAutofillToggled
|
|
||||||
{
|
|
||||||
get => _inlineAutofillToggled;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _inlineAutofillToggled, value))
|
|
||||||
{
|
|
||||||
var task = UpdateInlineAutofillToggledAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Accessibility
|
|
||||||
|
|
||||||
public ICommand ToggleAccessibilityCommand { get; }
|
|
||||||
|
|
||||||
public string AccessibilityDescriptionLabel
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_deviceActionService.SystemMajorVersion() <= 22)
|
|
||||||
{
|
|
||||||
// Android 5
|
|
||||||
return _i18nService.T("AccessibilityDescription");
|
|
||||||
}
|
|
||||||
if (_deviceActionService.SystemMajorVersion() == 23)
|
|
||||||
{
|
|
||||||
// Android 6
|
|
||||||
return _i18nService.T("AccessibilityDescription2");
|
|
||||||
}
|
|
||||||
if (_deviceActionService.SystemMajorVersion() == 24 || _deviceActionService.SystemMajorVersion() == 25)
|
|
||||||
{
|
|
||||||
// Android 7
|
|
||||||
return _i18nService.T("AccessibilityDescription3");
|
|
||||||
}
|
|
||||||
// Android 8+
|
|
||||||
return _i18nService.T("AccessibilityDescription4");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AccessibilityToggled
|
|
||||||
{
|
|
||||||
get => _accessibilityToggled;
|
|
||||||
set => SetProperty(ref _accessibilityToggled, value,
|
|
||||||
additionalPropertyNames: new string[]
|
|
||||||
{
|
|
||||||
nameof(DrawOverEnabled)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Draw-Over
|
|
||||||
|
|
||||||
public bool DrawOverVisible
|
|
||||||
{
|
|
||||||
get => _deviceActionService.SystemMajorVersion() >= 23;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DrawOverDescriptionLabel
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_deviceActionService.SystemMajorVersion() <= 23)
|
|
||||||
{
|
|
||||||
// Android 6
|
|
||||||
return _i18nService.T("DrawOverDescription");
|
|
||||||
}
|
|
||||||
if (_deviceActionService.SystemMajorVersion() == 24 || _deviceActionService.SystemMajorVersion() == 25)
|
|
||||||
{
|
|
||||||
// Android 7
|
|
||||||
return _i18nService.T("DrawOverDescription2");
|
|
||||||
}
|
|
||||||
// Android 8+
|
|
||||||
return _i18nService.T("DrawOverDescription3");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DrawOverEnabled
|
|
||||||
{
|
|
||||||
get => AccessibilityToggled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DrawOverToggled
|
|
||||||
{
|
|
||||||
get => _drawOverToggled;
|
|
||||||
set => SetProperty(ref _drawOverToggled, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public async Task InitAsync()
|
|
||||||
{
|
|
||||||
InlineAutofillToggled = await _stateService.GetInlineAutofillEnabledAsync() ?? true;
|
|
||||||
_inited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleAutofillService()
|
|
||||||
{
|
|
||||||
if (!AutofillServiceToggled)
|
|
||||||
{
|
|
||||||
_deviceActionService.OpenAutofillSettings();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_autofillHandler.DisableAutofillService();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleInlineAutofill()
|
|
||||||
{
|
|
||||||
if (!InlineAutofillEnabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
InlineAutofillToggled = !InlineAutofillToggled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ToggleAccessibilityAsync()
|
|
||||||
{
|
|
||||||
if (!_autofillHandler.AutofillAccessibilityServiceRunning())
|
|
||||||
{
|
|
||||||
var accept = await _platformUtilsService.ShowDialogAsync(AppResources.AccessibilityDisclosureText,
|
|
||||||
AppResources.AccessibilityServiceDisclosure, AppResources.Accept,
|
|
||||||
AppResources.Decline);
|
|
||||||
if (!accept)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_deviceActionService.OpenAccessibilitySettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleDrawOver()
|
|
||||||
{
|
|
||||||
if (!DrawOverEnabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_deviceActionService.OpenAccessibilityOverlayPermissionSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateEnabled()
|
|
||||||
{
|
|
||||||
AutofillServiceToggled =
|
|
||||||
_autofillHandler.SupportsAutofillService() && _autofillHandler.AutofillServiceEnabled();
|
|
||||||
AccessibilityToggled = _autofillHandler.AutofillAccessibilityServiceRunning();
|
|
||||||
DrawOverToggled = _autofillHandler.AutofillAccessibilityOverlayPermitted();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateInlineAutofillToggledAsync()
|
|
||||||
{
|
|
||||||
if (_inited)
|
|
||||||
{
|
|
||||||
await _stateService.SetInlineAutofillEnabledAsync(InlineAutofillToggled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.OptionsPage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:OptionsPageViewModel"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:OptionsPageViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ContentPage.ToolbarItems>
|
|
||||||
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
|
|
||||||
</ContentPage.ToolbarItems>
|
|
||||||
|
|
||||||
<ScrollView Padding="0, 0, 0, 20">
|
|
||||||
<StackLayout Padding="0" Spacing="20">
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n Theme}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Picker
|
|
||||||
x:Name="_themePicker"
|
|
||||||
ItemsSource="{Binding ThemeOptions, Mode=OneTime}"
|
|
||||||
SelectedIndex="{Binding ThemeSelectedIndex}"
|
|
||||||
StyleClass="box-value" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
StyleClass="box-footer-label"
|
|
||||||
Text="{u:I18n ThemeDescription}" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
StyleClass="box"
|
|
||||||
IsVisible="{Binding ShowAutoDarkThemeOptions}">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n DefaultDarkTheme}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Picker
|
|
||||||
x:Name="_autoDarkThemePicker"
|
|
||||||
ItemsSource="{Binding AutoDarkThemeOptions, Mode=OneTime}"
|
|
||||||
SelectedIndex="{Binding AutoDarkThemeSelectedIndex}"
|
|
||||||
StyleClass="box-value" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
StyleClass="box-footer-label"
|
|
||||||
Text="{u:I18n DefaultDarkThemeDescription}" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n DefaultUriMatchDetection}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Picker
|
|
||||||
x:Name="_uriMatchPicker"
|
|
||||||
ItemsSource="{Binding UriMatchOptions, Mode=OneTime}"
|
|
||||||
SelectedIndex="{Binding UriMatchSelectedIndex}"
|
|
||||||
StyleClass="box-value" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n DefaultUriMatchDetectionDescription}"
|
|
||||||
StyleClass="box-footer-label" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ClearClipboard}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Picker
|
|
||||||
x:Name="_clearClipboardPicker"
|
|
||||||
ItemsSource="{Binding ClearClipboardOptions, Mode=OneTime}"
|
|
||||||
SelectedIndex="{Binding ClearClipboardSelectedIndex}"
|
|
||||||
StyleClass="box-value" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ClearClipboardDescription}"
|
|
||||||
StyleClass="box-footer-label" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-input, box-row-input-options-platform">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n Language}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Picker
|
|
||||||
x:Name="_languagePicker"
|
|
||||||
ItemsSource="{Binding LocalesOptions, Mode=OneTime}"
|
|
||||||
SelectedItem="{Binding SelectedLocale}"
|
|
||||||
ItemDisplayBinding="{Binding Value}"
|
|
||||||
StyleClass="box-value" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n LanguageChangeRequiresAppRestart}"
|
|
||||||
StyleClass="box-footer-label" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n CopyTotpAutomatically}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<Switch
|
|
||||||
IsToggled="{Binding AutoTotpCopy}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n CopyTotpAutomaticallyDescription}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ShowWebsiteIcons}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<Switch
|
|
||||||
IsToggled="{Binding Favicon}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n ShowWebsiteIconsDescription}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box" IsVisible="{Binding ShowAndroidAutofillSettings}">
|
|
||||||
<StackLayout StyleClass="box-row-header">
|
|
||||||
<Label Text="{u:I18n AutofillService, Header=True}"
|
|
||||||
StyleClass="box-header, box-header-platform" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n AskToAddLogin}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<Switch
|
|
||||||
IsToggled="{Binding AutofillSavePrompt}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n AskToAddLoginDescription}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box" IsVisible="{Binding ShowAndroidAutofillSettings}">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-input">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n AutofillBlockedUris}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Editor
|
|
||||||
x:Name="_autofillBlockedUrisEditor"
|
|
||||||
Text="{Binding AutofillBlockedUris}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
AutoSize="TextChanges"
|
|
||||||
IsSpellCheckEnabled="False"
|
|
||||||
IsTextPredictionEnabled="False"
|
|
||||||
Keyboard="Url"
|
|
||||||
Unfocused="AutofillBlockedUrisEditor_Unfocused" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n AutofillBlockedUrisDescription}"
|
|
||||||
StyleClass="box-footer-label" />
|
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.PlatformConfiguration;
|
|
||||||
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public partial class OptionsPage : BaseContentPage
|
|
||||||
{
|
|
||||||
private readonly IAutofillHandler _autofillHandler;
|
|
||||||
private readonly OptionsPageViewModel _vm;
|
|
||||||
|
|
||||||
public OptionsPage()
|
|
||||||
{
|
|
||||||
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
|
|
||||||
InitializeComponent();
|
|
||||||
_vm = BindingContext as OptionsPageViewModel;
|
|
||||||
_vm.Page = this;
|
|
||||||
_themePicker.ItemDisplayBinding = new Binding("Value");
|
|
||||||
_autoDarkThemePicker.ItemDisplayBinding = new Binding("Value");
|
|
||||||
_uriMatchPicker.ItemDisplayBinding = new Binding("Value");
|
|
||||||
_clearClipboardPicker.ItemDisplayBinding = new Binding("Value");
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
ToolbarItems.RemoveAt(0);
|
|
||||||
_vm.ShowAndroidAutofillSettings = _autofillHandler.SupportsAutofillService();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_themePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
|
||||||
_autoDarkThemePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
|
||||||
_uriMatchPicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
|
||||||
_clearClipboardPicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
|
||||||
_languagePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
|
||||||
{
|
|
||||||
base.OnAppearing();
|
|
||||||
await _vm.InitAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async override void OnDisappearing()
|
|
||||||
{
|
|
||||||
base.OnDisappearing();
|
|
||||||
await _vm.UpdateAutofillBlockedUris();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void AutofillBlockedUrisEditor_Unfocused(object sender, FocusEventArgs e)
|
|
||||||
{
|
|
||||||
await _vm.UpdateAutofillBlockedUris();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Close_Clicked(object sender, System.EventArgs e)
|
|
||||||
{
|
|
||||||
if (DoOnce())
|
|
||||||
{
|
|
||||||
await Navigation.PopModalAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,338 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class OptionsPageViewModel : BaseViewModel
|
|
||||||
{
|
|
||||||
private readonly IStateService _stateService;
|
|
||||||
private readonly IMessagingService _messagingService;
|
|
||||||
private readonly II18nService _i18nService;
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
|
|
||||||
private bool _autofillSavePrompt;
|
|
||||||
private string _autofillBlockedUris;
|
|
||||||
private bool _favicon;
|
|
||||||
private bool _autoTotpCopy;
|
|
||||||
private int _clearClipboardSelectedIndex;
|
|
||||||
private int _themeSelectedIndex;
|
|
||||||
private int _autoDarkThemeSelectedIndex;
|
|
||||||
private int _uriMatchSelectedIndex;
|
|
||||||
private KeyValuePair<string, string> _selectedLocale;
|
|
||||||
private bool _inited;
|
|
||||||
private bool _updatingAutofill;
|
|
||||||
private bool _showAndroidAutofillSettings;
|
|
||||||
|
|
||||||
public OptionsPageViewModel()
|
|
||||||
{
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
|
||||||
_i18nService = ServiceContainer.Resolve<II18nService>();
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>();
|
|
||||||
|
|
||||||
PageTitle = AppResources.Options;
|
|
||||||
var iosIos = Device.RuntimePlatform == Device.iOS;
|
|
||||||
|
|
||||||
ClearClipboardOptions = new List<KeyValuePair<int?, string>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<int?, string>(null, AppResources.Never),
|
|
||||||
new KeyValuePair<int?, string>(10, AppResources.TenSeconds),
|
|
||||||
new KeyValuePair<int?, string>(20, AppResources.TwentySeconds),
|
|
||||||
new KeyValuePair<int?, string>(30, AppResources.ThirtySeconds),
|
|
||||||
new KeyValuePair<int?, string>(60, AppResources.OneMinute)
|
|
||||||
};
|
|
||||||
if (!iosIos)
|
|
||||||
{
|
|
||||||
ClearClipboardOptions.Add(new KeyValuePair<int?, string>(120, AppResources.TwoMinutes));
|
|
||||||
ClearClipboardOptions.Add(new KeyValuePair<int?, string>(300, AppResources.FiveMinutes));
|
|
||||||
}
|
|
||||||
ThemeOptions = new List<KeyValuePair<string, string>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>(null, AppResources.ThemeDefault),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Light, AppResources.Light),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Dark, AppResources.Dark),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Black, AppResources.Black),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Nord, AppResources.Nord),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.SolarizedDark, AppResources.SolarizedDark),
|
|
||||||
};
|
|
||||||
AutoDarkThemeOptions = new List<KeyValuePair<string, string>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Dark, AppResources.Dark),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Black, AppResources.Black),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.Nord, AppResources.Nord),
|
|
||||||
new KeyValuePair<string, string>(ThemeManager.SolarizedDark, AppResources.SolarizedDark),
|
|
||||||
};
|
|
||||||
UriMatchOptions = new List<KeyValuePair<UriMatchType?, string>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.Domain, AppResources.BaseDomain),
|
|
||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.Host, AppResources.Host),
|
|
||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.StartsWith, AppResources.StartsWith),
|
|
||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.RegularExpression, AppResources.RegEx),
|
|
||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.Exact, AppResources.Exact),
|
|
||||||
new KeyValuePair<UriMatchType?, string>(UriMatchType.Never, AppResources.Never),
|
|
||||||
};
|
|
||||||
LocalesOptions = new List<KeyValuePair<string, string>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>(null, AppResources.DefaultSystem)
|
|
||||||
};
|
|
||||||
LocalesOptions.AddRange(_i18nService.LocaleNames.ToList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<KeyValuePair<int?, string>> ClearClipboardOptions { get; set; }
|
|
||||||
public List<KeyValuePair<string, string>> ThemeOptions { get; set; }
|
|
||||||
public List<KeyValuePair<string, string>> AutoDarkThemeOptions { get; set; }
|
|
||||||
public List<KeyValuePair<UriMatchType?, string>> UriMatchOptions { get; set; }
|
|
||||||
public List<KeyValuePair<string, string>> LocalesOptions { get; }
|
|
||||||
|
|
||||||
public int ClearClipboardSelectedIndex
|
|
||||||
{
|
|
||||||
get => _clearClipboardSelectedIndex;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _clearClipboardSelectedIndex, value))
|
|
||||||
{
|
|
||||||
SaveClipboardChangedAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ThemeSelectedIndex
|
|
||||||
{
|
|
||||||
get => _themeSelectedIndex;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _themeSelectedIndex, value,
|
|
||||||
additionalPropertyNames: new[] { nameof(ShowAutoDarkThemeOptions) })
|
|
||||||
)
|
|
||||||
{
|
|
||||||
SaveThemeAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowAutoDarkThemeOptions => ThemeOptions[ThemeSelectedIndex].Key == null;
|
|
||||||
|
|
||||||
public int AutoDarkThemeSelectedIndex
|
|
||||||
{
|
|
||||||
get => _autoDarkThemeSelectedIndex;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _autoDarkThemeSelectedIndex, value))
|
|
||||||
{
|
|
||||||
SaveThemeAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int UriMatchSelectedIndex
|
|
||||||
{
|
|
||||||
get => _uriMatchSelectedIndex;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _uriMatchSelectedIndex, value))
|
|
||||||
{
|
|
||||||
SaveDefaultUriAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyValuePair<string, string> SelectedLocale
|
|
||||||
{
|
|
||||||
get => _selectedLocale;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _selectedLocale, value))
|
|
||||||
{
|
|
||||||
UpdateCurrentLocaleAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Favicon
|
|
||||||
{
|
|
||||||
get => _favicon;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _favicon, value))
|
|
||||||
{
|
|
||||||
UpdateFaviconAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AutoTotpCopy
|
|
||||||
{
|
|
||||||
get => _autoTotpCopy;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _autoTotpCopy, value))
|
|
||||||
{
|
|
||||||
UpdateAutoTotpCopyAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AutofillSavePrompt
|
|
||||||
{
|
|
||||||
get => _autofillSavePrompt;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _autofillSavePrompt, value))
|
|
||||||
{
|
|
||||||
UpdateAutofillSavePromptAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string AutofillBlockedUris
|
|
||||||
{
|
|
||||||
get => _autofillBlockedUris;
|
|
||||||
set => SetProperty(ref _autofillBlockedUris, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowAndroidAutofillSettings
|
|
||||||
{
|
|
||||||
get => _showAndroidAutofillSettings;
|
|
||||||
set => SetProperty(ref _showAndroidAutofillSettings, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InitAsync()
|
|
||||||
{
|
|
||||||
AutofillSavePrompt = !(await _stateService.GetAutofillDisableSavePromptAsync()).GetValueOrDefault();
|
|
||||||
|
|
||||||
var blockedUrisList = await _stateService.GetAutofillBlacklistedUrisAsync();
|
|
||||||
AutofillBlockedUris = blockedUrisList != null ? string.Join(", ", blockedUrisList) : null;
|
|
||||||
|
|
||||||
AutoTotpCopy = !(await _stateService.GetDisableAutoTotpCopyAsync() ?? false);
|
|
||||||
|
|
||||||
Favicon = !(await _stateService.GetDisableFaviconAsync()).GetValueOrDefault();
|
|
||||||
|
|
||||||
var theme = await _stateService.GetThemeAsync();
|
|
||||||
ThemeSelectedIndex = ThemeOptions.FindIndex(k => k.Key == theme);
|
|
||||||
|
|
||||||
var autoDarkTheme = await _stateService.GetAutoDarkThemeAsync() ?? "dark";
|
|
||||||
AutoDarkThemeSelectedIndex = AutoDarkThemeOptions.FindIndex(k => k.Key == autoDarkTheme);
|
|
||||||
|
|
||||||
var defaultUriMatch = await _stateService.GetDefaultUriMatchAsync();
|
|
||||||
UriMatchSelectedIndex = defaultUriMatch == null ? 0 :
|
|
||||||
UriMatchOptions.FindIndex(k => (int?)k.Key == defaultUriMatch);
|
|
||||||
|
|
||||||
var clearClipboard = await _stateService.GetClearClipboardAsync();
|
|
||||||
ClearClipboardSelectedIndex = ClearClipboardOptions.FindIndex(k => k.Key == clearClipboard);
|
|
||||||
|
|
||||||
var appLocale = _stateService.GetLocale();
|
|
||||||
SelectedLocale = appLocale == null ? LocalesOptions.First() : LocalesOptions.FirstOrDefault(kv => kv.Key == appLocale);
|
|
||||||
|
|
||||||
_inited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateAutoTotpCopyAsync()
|
|
||||||
{
|
|
||||||
if (_inited)
|
|
||||||
{
|
|
||||||
// TODO: [PS-961] Fix negative function names
|
|
||||||
await _stateService.SetDisableAutoTotpCopyAsync(!AutoTotpCopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateFaviconAsync()
|
|
||||||
{
|
|
||||||
if (_inited)
|
|
||||||
{
|
|
||||||
// TODO: [PS-961] Fix negative function names
|
|
||||||
await _stateService.SetDisableFaviconAsync(!Favicon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveClipboardChangedAsync()
|
|
||||||
{
|
|
||||||
if (_inited && ClearClipboardSelectedIndex > -1)
|
|
||||||
{
|
|
||||||
await _stateService.SetClearClipboardAsync(ClearClipboardOptions[ClearClipboardSelectedIndex].Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveThemeAsync()
|
|
||||||
{
|
|
||||||
if (_inited && ThemeSelectedIndex > -1)
|
|
||||||
{
|
|
||||||
await _stateService.SetThemeAsync(ThemeOptions[ThemeSelectedIndex].Key);
|
|
||||||
await _stateService.SetAutoDarkThemeAsync(AutoDarkThemeOptions[AutoDarkThemeSelectedIndex].Key);
|
|
||||||
ThemeManager.SetTheme(Application.Current.Resources);
|
|
||||||
_messagingService.Send("updatedTheme");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveDefaultUriAsync()
|
|
||||||
{
|
|
||||||
if (_inited && UriMatchSelectedIndex > -1)
|
|
||||||
{
|
|
||||||
await _stateService.SetDefaultUriMatchAsync((int?)UriMatchOptions[UriMatchSelectedIndex].Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateAutofillSavePromptAsync()
|
|
||||||
{
|
|
||||||
if (_inited)
|
|
||||||
{
|
|
||||||
// TODO: [PS-961] Fix negative function names
|
|
||||||
await _stateService.SetAutofillDisableSavePromptAsync(!AutofillSavePrompt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateAutofillBlockedUris()
|
|
||||||
{
|
|
||||||
if (_inited)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(AutofillBlockedUris))
|
|
||||||
{
|
|
||||||
await _stateService.SetAutofillBlacklistedUrisAsync(null);
|
|
||||||
AutofillBlockedUris = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var csv = AutofillBlockedUris;
|
|
||||||
var urisList = new List<string>();
|
|
||||||
foreach (var uri in csv.Split(','))
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(uri))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var cleanedUri = uri.Replace(System.Environment.NewLine, string.Empty).Trim();
|
|
||||||
if (!cleanedUri.StartsWith("http://") && !cleanedUri.StartsWith("https://") &&
|
|
||||||
!cleanedUri.StartsWith(Constants.AndroidAppProtocol))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
urisList.Add(cleanedUri);
|
|
||||||
}
|
|
||||||
await _stateService.SetAutofillBlacklistedUrisAsync(urisList);
|
|
||||||
AutofillBlockedUris = string.Join(", ", urisList);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task UpdateCurrentLocaleAsync()
|
|
||||||
{
|
|
||||||
if (!_inited)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_stateService.SetLocale(SelectedLocale.Key);
|
|
||||||
|
|
||||||
await _platformUtilsService.ShowDialogAsync(string.Format(AppResources.LanguageChangeXDescription, SelectedLocale.Value), AppResources.Language, AppResources.Ok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public interface ISettingsPageListItem
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<pages:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.SettingsPage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:SettingsPageViewModel"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:SettingsPageViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ContentPage.Resources>
|
|
||||||
<ResourceDictionary>
|
|
||||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
|
||||||
<u:StringHasValueConverter x:Key="stringHasValue" />
|
|
||||||
|
|
||||||
<DataTemplate
|
|
||||||
x:Key="regularTemplate"
|
|
||||||
x:DataType="pages:SettingsPageListItem">
|
|
||||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
|
||||||
StyleClass="list-row, list-row-platform">
|
|
||||||
<Frame
|
|
||||||
IsVisible="{Binding UseFrame}"
|
|
||||||
Padding="10"
|
|
||||||
HasShadow="False"
|
|
||||||
BackgroundColor="Transparent"
|
|
||||||
BorderColor="{DynamicResource PrimaryColor}">
|
|
||||||
<Label
|
|
||||||
Text="{Binding Name, Mode=OneWay}"
|
|
||||||
StyleClass="text-muted, text-sm, text-bold"
|
|
||||||
HorizontalTextAlignment="Center" />
|
|
||||||
</Frame>
|
|
||||||
<Label 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}"
|
|
||||||
IsVisible="{Binding ShowSubLabel}"
|
|
||||||
HorizontalOptions="End"
|
|
||||||
HorizontalTextAlignment="End"
|
|
||||||
VerticalOptions="CenterAndExpand"
|
|
||||||
TextColor="{Binding SubLabelColor}"
|
|
||||||
StyleClass="list-sub" />
|
|
||||||
</controls:ExtendedStackLayout>
|
|
||||||
</DataTemplate>
|
|
||||||
<DataTemplate
|
|
||||||
x:Key="timePickerTemplate"
|
|
||||||
x:DataType="pages:SettingsPageListItem">
|
|
||||||
<controls:ExtendedStackLayout Orientation="Horizontal"
|
|
||||||
StyleClass="list-row, list-row-platform">
|
|
||||||
<Frame
|
|
||||||
IsVisible="{Binding UseFrame}"
|
|
||||||
Padding="10"
|
|
||||||
HasShadow="False"
|
|
||||||
BackgroundColor="Transparent"
|
|
||||||
BorderColor="{DynamicResource PrimaryColor}">
|
|
||||||
<Label
|
|
||||||
Text="{Binding Name, Mode=OneWay}"
|
|
||||||
StyleClass="text-muted, text-sm, text-bold"
|
|
||||||
HorizontalTextAlignment="Center" />
|
|
||||||
</Frame>
|
|
||||||
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
|
|
||||||
Text="{Binding Name, Mode=OneWay}"
|
|
||||||
LineBreakMode="{Binding LineBreakMode}"
|
|
||||||
HorizontalOptions="StartAndExpand"
|
|
||||||
VerticalOptions="CenterAndExpand"
|
|
||||||
StyleClass="list-title"/>
|
|
||||||
<TimePicker Time="{Binding Time}" Format="HH:mm"
|
|
||||||
PropertyChanged="OnTimePickerPropertyChanged"
|
|
||||||
HorizontalOptions="End"
|
|
||||||
VerticalOptions="Center"
|
|
||||||
FontSize="Small"
|
|
||||||
TextColor="{Binding SubLabelColor}"
|
|
||||||
StyleClass="list-sub" Margin="-5"/>
|
|
||||||
<controls:ExtendedStackLayout.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Tapped="ActivateTimePicker"/>
|
|
||||||
</controls:ExtendedStackLayout.GestureRecognizers>
|
|
||||||
</controls:ExtendedStackLayout>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<DataTemplate
|
|
||||||
x:Key="headerTemplate"
|
|
||||||
x:DataType="pages:SettingsPageHeaderListItem">
|
|
||||||
<StackLayout
|
|
||||||
Padding="0" Spacing="0" VerticalOptions="FillAndExpand"
|
|
||||||
StyleClass="list-row-header-container, list-row-header-container-platform">
|
|
||||||
<BoxView
|
|
||||||
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
|
|
||||||
<StackLayout StyleClass="list-row-header, list-row-header-platform">
|
|
||||||
<Label
|
|
||||||
Text="{Binding Title}"
|
|
||||||
StyleClass="list-header, list-header-platform" />
|
|
||||||
</StackLayout>
|
|
||||||
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
|
|
||||||
</StackLayout>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<pages:SettingsPageListItemSelector
|
|
||||||
x:Key="listItemDataTemplateSelector"
|
|
||||||
HeaderTemplate="{StaticResource headerTemplate}"
|
|
||||||
RegularTemplate="{StaticResource regularTemplate}"
|
|
||||||
TimePickerTemplate="{StaticResource timePickerTemplate}" />
|
|
||||||
</ResourceDictionary>
|
|
||||||
</ContentPage.Resources>
|
|
||||||
|
|
||||||
<controls:ExtendedCollectionView
|
|
||||||
ItemsSource="{Binding GroupedItems}"
|
|
||||||
VerticalOptions="FillAndExpand"
|
|
||||||
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
|
|
||||||
SelectionMode="Single"
|
|
||||||
SelectionChanged="RowSelected"
|
|
||||||
StyleClass="list, list-platform"
|
|
||||||
ExtraDataForLogging="Settings Page" />
|
|
||||||
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public partial class SettingsPage : BaseContentPage
|
|
||||||
{
|
|
||||||
private readonly TabsPage _tabsPage;
|
|
||||||
private SettingsPageViewModel _vm;
|
|
||||||
|
|
||||||
public SettingsPage(TabsPage tabsPage)
|
|
||||||
{
|
|
||||||
_tabsPage = tabsPage;
|
|
||||||
InitializeComponent();
|
|
||||||
_vm = BindingContext as SettingsPageViewModel;
|
|
||||||
_vm.Page = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InitAsync()
|
|
||||||
{
|
|
||||||
await _vm.InitAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BuildList()
|
|
||||||
{
|
|
||||||
_vm.BuildList();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnBackButtonPressed()
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.Android && _tabsPage != null)
|
|
||||||
{
|
|
||||||
_tabsPage.ResetToVaultPage();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return base.OnBackButtonPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActivateTimePicker(object sender, EventArgs args)
|
|
||||||
{
|
|
||||||
var stackLayout = (ExtendedStackLayout)sender;
|
|
||||||
SettingsPageListItem item = (SettingsPageListItem)stackLayout.BindingContext;
|
|
||||||
if (item.ShowTimeInput)
|
|
||||||
{
|
|
||||||
var timePicker = stackLayout.Children.Where(x => x is TimePicker).FirstOrDefault();
|
|
||||||
((TimePicker)timePicker)?.Focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)
|
|
||||||
{
|
|
||||||
var s = (TimePicker)sender;
|
|
||||||
var time = s.Time.TotalMinutes;
|
|
||||||
if (s.IsFocused && args.PropertyName == "Time")
|
|
||||||
{
|
|
||||||
await _vm.VaultTimeoutAsync(false, (int)time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RowSelected(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
((ExtendedCollectionView)sender).SelectedItem = null;
|
|
||||||
if (e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item)
|
|
||||||
{
|
|
||||||
_vm?.ExecuteSettingItemCommand.Execute(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SettingsPageHeaderListItem : ISettingsPageListItem
|
|
||||||
{
|
|
||||||
public SettingsPageHeaderListItem(string title)
|
|
||||||
{
|
|
||||||
Title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Title { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SettingsPageListGroup : List<SettingsPageListItem>
|
|
||||||
{
|
|
||||||
public SettingsPageListGroup(List<SettingsPageListItem> groupItems, string name, bool doUpper = true,
|
|
||||||
bool first = false)
|
|
||||||
{
|
|
||||||
AddRange(groupItems);
|
|
||||||
if (string.IsNullOrWhiteSpace(name))
|
|
||||||
{
|
|
||||||
Name = "-";
|
|
||||||
}
|
|
||||||
else if (doUpper)
|
|
||||||
{
|
|
||||||
Name = name.ToUpperInvariant();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
First = first;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool First { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SettingsPageListItem : ISettingsPageListItem
|
|
||||||
{
|
|
||||||
public string Icon { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string SubLabel { get; set; }
|
|
||||||
public TimeSpan? Time { get; set; }
|
|
||||||
public bool UseFrame { get; set; }
|
|
||||||
public Func<Task> ExecuteAsync { get; set; }
|
|
||||||
|
|
||||||
public bool SubLabelTextEnabled => SubLabel == AppResources.On;
|
|
||||||
public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
|
|
||||||
public bool ShowSubLabel => SubLabel.Length != 0;
|
|
||||||
public bool ShowTimeInput => Time != null;
|
|
||||||
public Color SubLabelColor => SubLabelTextEnabled ?
|
|
||||||
ThemeManager.GetResourceColor("SuccessColor") :
|
|
||||||
ThemeManager.GetResourceColor("MutedColor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SettingsPageListItemSelector : DataTemplateSelector
|
|
||||||
{
|
|
||||||
public DataTemplate HeaderTemplate { get; set; }
|
|
||||||
public DataTemplate RegularTemplate { get; set; }
|
|
||||||
public DataTemplate TimePickerTemplate { get; set; }
|
|
||||||
|
|
||||||
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
|
||||||
{
|
|
||||||
if (item is SettingsPageHeaderListItem)
|
|
||||||
{
|
|
||||||
return HeaderTemplate;
|
|
||||||
}
|
|
||||||
if (item is SettingsPageListItem listItem)
|
|
||||||
{
|
|
||||||
return listItem.ShowTimeInput ? TimePickerTemplate : RegularTemplate;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,873 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Pages.Accounts;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Models.Domain;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.CommunityToolkit.ObjectModel;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SettingsPageViewModel : BaseViewModel
|
|
||||||
{
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly ICryptoService _cryptoService;
|
|
||||||
private readonly IStateService _stateService;
|
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly IAutofillHandler _autofillHandler;
|
|
||||||
private readonly IEnvironmentService _environmentService;
|
|
||||||
private readonly IMessagingService _messagingService;
|
|
||||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
|
||||||
private readonly ISyncService _syncService;
|
|
||||||
private readonly IBiometricService _biometricService;
|
|
||||||
private readonly IPolicyService _policyService;
|
|
||||||
private readonly ILocalizeService _localizeService;
|
|
||||||
private readonly IKeyConnectorService _keyConnectorService;
|
|
||||||
private readonly IClipboardService _clipboardService;
|
|
||||||
private readonly ILogger _loggerService;
|
|
||||||
private readonly IPushNotificationService _pushNotificationService;
|
|
||||||
private readonly IAuthService _authService;
|
|
||||||
private readonly IWatchDeviceService _watchDeviceService;
|
|
||||||
private const int CustomVaultTimeoutValue = -100;
|
|
||||||
|
|
||||||
private bool _supportsBiometric;
|
|
||||||
private bool _pin;
|
|
||||||
private bool _biometric;
|
|
||||||
private bool _screenCaptureAllowed;
|
|
||||||
private string _lastSyncDate;
|
|
||||||
private string _vaultTimeoutDisplayValue;
|
|
||||||
private string _vaultTimeoutActionDisplayValue;
|
|
||||||
private bool _showChangeMasterPassword;
|
|
||||||
private bool _reportLoggingEnabled;
|
|
||||||
private bool _approvePasswordlessLoginRequests;
|
|
||||||
private bool _shouldConnectToWatch;
|
|
||||||
private readonly static List<KeyValuePair<string, int?>> VaultTimeoutOptions =
|
|
||||||
new List<KeyValuePair<string, int?>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, int?>(AppResources.Immediately, 0),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.OneMinute, 1),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.FiveMinutes, 5),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.FifteenMinutes, 15),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.ThirtyMinutes, 30),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.OneHour, 60),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.FourHours, 240),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.OnRestart, -1),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.Never, null),
|
|
||||||
new KeyValuePair<string, int?>(AppResources.Custom, CustomVaultTimeoutValue),
|
|
||||||
};
|
|
||||||
private readonly static List<KeyValuePair<string, VaultTimeoutAction>> VaultTimeoutActionOptions =
|
|
||||||
new List<KeyValuePair<string, VaultTimeoutAction>>
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, VaultTimeoutAction>(AppResources.Lock, VaultTimeoutAction.Lock),
|
|
||||||
new KeyValuePair<string, VaultTimeoutAction>(AppResources.LogOut, VaultTimeoutAction.Logout),
|
|
||||||
};
|
|
||||||
|
|
||||||
private Policy _vaultTimeoutPolicy;
|
|
||||||
private int? _vaultTimeout;
|
|
||||||
private List<KeyValuePair<string, int?>> _vaultTimeoutOptions = VaultTimeoutOptions;
|
|
||||||
private List<KeyValuePair<string, VaultTimeoutAction>> _vaultTimeoutActionOptions = VaultTimeoutActionOptions;
|
|
||||||
|
|
||||||
public SettingsPageViewModel()
|
|
||||||
{
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_autofillHandler = ServiceContainer.Resolve<IAutofillHandler>();
|
|
||||||
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
|
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
|
||||||
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
|
||||||
_biometricService = ServiceContainer.Resolve<IBiometricService>("biometricService");
|
|
||||||
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
|
|
||||||
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
|
|
||||||
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
|
|
||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
|
||||||
_loggerService = ServiceContainer.Resolve<ILogger>("logger");
|
|
||||||
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
|
||||||
_authService = ServiceContainer.Resolve<IAuthService>();
|
|
||||||
_watchDeviceService = ServiceContainer.Resolve<IWatchDeviceService>();
|
|
||||||
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
|
|
||||||
PageTitle = AppResources.Settings;
|
|
||||||
|
|
||||||
ExecuteSettingItemCommand = new AsyncCommand<SettingsPageListItem>(item => item.ExecuteAsync(), onException: _loggerService.Exception, allowsMultipleExecutions: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableRangeCollection<ISettingsPageListItem> GroupedItems { get; set; }
|
|
||||||
|
|
||||||
public IAsyncCommand<SettingsPageListItem> ExecuteSettingItemCommand { get; }
|
|
||||||
|
|
||||||
public async Task InitAsync()
|
|
||||||
{
|
|
||||||
_supportsBiometric = await _platformUtilsService.SupportsBiometricAsync();
|
|
||||||
var lastSync = await _syncService.GetLastSyncAsync();
|
|
||||||
if (lastSync != null)
|
|
||||||
{
|
|
||||||
lastSync = lastSync.Value.ToLocalTime();
|
|
||||||
_lastSyncDate = string.Format("{0} {1}",
|
|
||||||
_localizeService.GetLocaleShortDate(lastSync.Value),
|
|
||||||
_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 policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
|
||||||
_vaultTimeoutOptions = _vaultTimeoutOptions.Where(t =>
|
|
||||||
t.Value <= policyMinutes &&
|
|
||||||
(t.Value > 0 || t.Value == CustomVaultTimeoutValue) &&
|
|
||||||
t.Value != null).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
var pinSet = await _vaultTimeoutService.IsPinLockSetAsync();
|
|
||||||
_pin = pinSet.Item1 || pinSet.Item2;
|
|
||||||
_biometric = await _vaultTimeoutService.IsBiometricLockSetAsync();
|
|
||||||
_screenCaptureAllowed = await _stateService.GetScreenCaptureAllowedAsync();
|
|
||||||
|
|
||||||
if (_vaultTimeoutDisplayValue == null)
|
|
||||||
{
|
|
||||||
_vaultTimeoutDisplayValue = AppResources.Custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
_showChangeMasterPassword = IncludeLinksWithSubscriptionInfo() &&
|
|
||||||
!await _keyConnectorService.GetUsesKeyConnector();
|
|
||||||
_reportLoggingEnabled = await _loggerService.IsEnabled();
|
|
||||||
_approvePasswordlessLoginRequests = await _stateService.GetApprovePasswordlessLoginsAsync();
|
|
||||||
_shouldConnectToWatch = await _stateService.GetShouldConnectToWatchAsync();
|
|
||||||
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task AboutAsync()
|
|
||||||
{
|
|
||||||
var debugText = string.Format("{0}: {1} ({2})", AppResources.Version,
|
|
||||||
_platformUtilsService.GetApplicationVersion(), _deviceActionService.GetBuildNumber());
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
var pushNotificationsRegistered = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService").IsRegisteredForPush;
|
|
||||||
var pnServerRegDate = await _stateService.GetPushLastRegistrationDateAsync();
|
|
||||||
var pnServerError = await _stateService.GetPushInstallationRegistrationErrorAsync();
|
|
||||||
|
|
||||||
var pnServerRegDateMessage = default(DateTime) == pnServerRegDate ? "-" : $"{pnServerRegDate.GetValueOrDefault().ToShortDateString()}-{pnServerRegDate.GetValueOrDefault().ToShortTimeString()} UTC";
|
|
||||||
var errorMessage = string.IsNullOrEmpty(pnServerError) ? string.Empty : $"Push Notifications Server Registration error: {pnServerError}";
|
|
||||||
|
|
||||||
var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}\nPush Notifications registered:{2}\nPush Notifications Server Last Date :{3}\n{4}", DateTime.Now.Year, debugText, pushNotificationsRegistered, pnServerRegDateMessage, errorMessage);
|
|
||||||
#else
|
|
||||||
var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}", DateTime.Now.Year, debugText);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var copy = await _platformUtilsService.ShowDialogAsync(text, AppResources.Bitwarden, AppResources.Copy,
|
|
||||||
AppResources.Close);
|
|
||||||
if (copy)
|
|
||||||
{
|
|
||||||
await _clipboardService.CopyTextAsync(debugText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Help()
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri("https://bitwarden.com/help/");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task FingerprintAsync()
|
|
||||||
{
|
|
||||||
List<string> fingerprint;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fingerprint = await _cryptoService.GetFingerprintAsync(await _stateService.GetActiveUserIdAsync());
|
|
||||||
}
|
|
||||||
catch (Exception e) when (e.Message == "No public key available.")
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var phrase = string.Join("-", fingerprint);
|
|
||||||
var text = string.Format("{0}:\n\n{1}", AppResources.YourAccountsFingerprint, phrase);
|
|
||||||
var learnMore = await _platformUtilsService.ShowDialogAsync(text, AppResources.FingerprintPhrase,
|
|
||||||
AppResources.LearnMore, AppResources.Close);
|
|
||||||
if (learnMore)
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri("https://bitwarden.com/help/fingerprint-phrase/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Rate()
|
|
||||||
{
|
|
||||||
_deviceActionService.RateApp();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Import()
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri("https://bitwarden.com/help/import-data/");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WebVault()
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri(_environmentService.GetWebVaultUrl());
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ShareAsync()
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LearnOrgConfirmation,
|
|
||||||
AppResources.LearnOrg, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (confirmed)
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri("https://bitwarden.com/help/about-organizations/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task TwoStepAsync()
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.TwoStepLoginConfirmation,
|
|
||||||
AppResources.TwoStepLogin, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (confirmed)
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri($"{_environmentService.GetWebVaultUrl()}/#/settings");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ChangePasswordAsync()
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.ChangePasswordConfirmation,
|
|
||||||
AppResources.ChangeMasterPassword, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (confirmed)
|
|
||||||
{
|
|
||||||
_platformUtilsService.LaunchUri($"{_environmentService.GetWebVaultUrl()}/#/settings");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task LogOutAsync()
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LogoutConfirmation,
|
|
||||||
AppResources.LogOut, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (confirmed)
|
|
||||||
{
|
|
||||||
_messagingService.Send("logout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task LockAsync()
|
|
||||||
{
|
|
||||||
await _vaultTimeoutService.LockAsync(true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task VaultTimeoutAsync(bool promptOptions = true, int? newTimeout = 0)
|
|
||||||
{
|
|
||||||
var oldTimeout = _vaultTimeout;
|
|
||||||
|
|
||||||
var options = _vaultTimeoutOptions.Select(
|
|
||||||
o => o.Key == _vaultTimeoutDisplayValue ? $"✓ {o.Key}" : o.Key).ToArray();
|
|
||||||
if (promptOptions)
|
|
||||||
{
|
|
||||||
var selection = await Page.DisplayActionSheet(AppResources.VaultTimeout,
|
|
||||||
AppResources.Cancel, null, options);
|
|
||||||
if (selection == null || selection == AppResources.Cancel)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var cleanSelection = selection.Replace("✓ ", string.Empty);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.NeverLockWarning,
|
|
||||||
AppResources.Warning, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (!confirmed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_vaultTimeoutDisplayValue = selectionOption.Key;
|
|
||||||
newTimeout = selectionOption.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_vaultTimeoutPolicy != null)
|
|
||||||
{
|
|
||||||
var maximumTimeout = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
|
||||||
|
|
||||||
if (newTimeout > maximumTimeout)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.VaultTimeoutToLarge, AppResources.Warning);
|
|
||||||
var timeout = await _vaultTimeoutService.GetVaultTimeout();
|
|
||||||
_vaultTimeoutDisplayValue = _vaultTimeoutOptions.FirstOrDefault(o => o.Value == timeout).Key ??
|
|
||||||
AppResources.Custom;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(newTimeout,
|
|
||||||
GetVaultTimeoutActionFromKey(_vaultTimeoutActionDisplayValue));
|
|
||||||
|
|
||||||
if (newTimeout != CustomVaultTimeoutValue)
|
|
||||||
{
|
|
||||||
_vaultTimeout = newTimeout;
|
|
||||||
}
|
|
||||||
if (oldTimeout != newTimeout)
|
|
||||||
{
|
|
||||||
await Device.InvokeOnMainThreadAsync(BuildList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task LoggerReportingAsync()
|
|
||||||
{
|
|
||||||
var options = new[]
|
|
||||||
{
|
|
||||||
CreateSelectableOption(AppResources.Yes, _reportLoggingEnabled),
|
|
||||||
CreateSelectableOption(AppResources.No, !_reportLoggingEnabled),
|
|
||||||
};
|
|
||||||
|
|
||||||
var selection = await Page.DisplayActionSheet(AppResources.SubmitCrashLogsDescription, AppResources.Cancel, null, options);
|
|
||||||
|
|
||||||
if (selection == null || selection == AppResources.Cancel)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _loggerService.SetEnabled(CompareSelection(selection, AppResources.Yes));
|
|
||||||
_reportLoggingEnabled = await _loggerService.IsEnabled();
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ApproveLoginRequestsAsync()
|
|
||||||
{
|
|
||||||
var options = new[]
|
|
||||||
{
|
|
||||||
CreateSelectableOption(AppResources.Yes, _approvePasswordlessLoginRequests),
|
|
||||||
CreateSelectableOption(AppResources.No, !_approvePasswordlessLoginRequests),
|
|
||||||
};
|
|
||||||
|
|
||||||
var selection = await Page.DisplayActionSheet(AppResources.UseThisDeviceToApproveLoginRequestsMadeFromOtherDevices, AppResources.Cancel, null, options);
|
|
||||||
|
|
||||||
if (selection == null || selection == AppResources.Cancel)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_approvePasswordlessLoginRequests = CompareSelection(selection, AppResources.Yes);
|
|
||||||
await _stateService.SetApprovePasswordlessLoginsAsync(_approvePasswordlessLoginRequests);
|
|
||||||
|
|
||||||
BuildList();
|
|
||||||
|
|
||||||
if (!_approvePasswordlessLoginRequests || await _pushNotificationService.AreNotificationsSettingsEnabledAsync())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var openAppSettingsResult = await _platformUtilsService.ShowDialogAsync(AppResources.ReceivePushNotificationsForNewLoginRequests, title: string.Empty, confirmText: AppResources.Settings, cancelText: AppResources.NoThanks);
|
|
||||||
if (openAppSettingsResult)
|
|
||||||
{
|
|
||||||
_deviceActionService.OpenAppSettings();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task VaultTimeoutActionAsync()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
if (selection == null || selection == AppResources.Cancel)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var cleanSelection = selection.Replace("✓ ", string.Empty);
|
|
||||||
if (cleanSelection == AppResources.LogOut)
|
|
||||||
{
|
|
||||||
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.VaultTimeoutLogOutConfirmation,
|
|
||||||
AppResources.Warning, AppResources.Yes, AppResources.Cancel);
|
|
||||||
if (!confirmed)
|
|
||||||
{
|
|
||||||
// Reset to lock and continue process as if lock were selected
|
|
||||||
cleanSelection = AppResources.Lock;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var selectionOption = _vaultTimeoutActionOptions.FirstOrDefault(o => o.Key == cleanSelection);
|
|
||||||
var changed = _vaultTimeoutActionDisplayValue != selectionOption.Key;
|
|
||||||
_vaultTimeoutActionDisplayValue = selectionOption.Key;
|
|
||||||
await _vaultTimeoutService.SetVaultTimeoutOptionsAsync(_vaultTimeout,
|
|
||||||
selectionOption.Value);
|
|
||||||
if (changed)
|
|
||||||
{
|
|
||||||
_messagingService.Send("vaultTimeoutActionChanged");
|
|
||||||
}
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdatePinAsync()
|
|
||||||
{
|
|
||||||
_pin = !_pin;
|
|
||||||
if (_pin)
|
|
||||||
{
|
|
||||||
var pin = await _deviceActionService.DisplayPromptAync(AppResources.EnterPIN,
|
|
||||||
AppResources.SetPINDescription, null, AppResources.Submit, AppResources.Cancel, true);
|
|
||||||
if (!string.IsNullOrWhiteSpace(pin))
|
|
||||||
{
|
|
||||||
var masterPassOnRestart = false;
|
|
||||||
if (!await _keyConnectorService.GetUsesKeyConnector())
|
|
||||||
{
|
|
||||||
masterPassOnRestart = await _platformUtilsService.ShowDialogAsync(
|
|
||||||
AppResources.PINRequireMasterPasswordRestart, AppResources.UnlockWithPIN,
|
|
||||||
AppResources.Yes, AppResources.No);
|
|
||||||
}
|
|
||||||
|
|
||||||
var kdfConfig = await _stateService.GetActiveUserCustomDataAsync(a => new KdfConfig(a?.Profile));
|
|
||||||
var email = await _stateService.GetEmailAsync();
|
|
||||||
var pinKey = await _cryptoService.MakePinKeyAysnc(pin, email, kdfConfig);
|
|
||||||
var key = await _cryptoService.GetKeyAsync();
|
|
||||||
var pinProtectedKey = await _cryptoService.EncryptAsync(key.Key, pinKey);
|
|
||||||
|
|
||||||
if (masterPassOnRestart)
|
|
||||||
{
|
|
||||||
var encPin = await _cryptoService.EncryptAsync(pin);
|
|
||||||
await _stateService.SetProtectedPinAsync(encPin.EncryptedString);
|
|
||||||
await _stateService.SetPinProtectedKeyAsync(pinProtectedKey);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _stateService.SetPinProtectedAsync(pinProtectedKey.EncryptedString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pin = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!_pin)
|
|
||||||
{
|
|
||||||
await _cryptoService.ClearPinProtectedKeyAsync();
|
|
||||||
await _vaultTimeoutService.ClearAsync();
|
|
||||||
}
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateBiometricAsync()
|
|
||||||
{
|
|
||||||
var current = _biometric;
|
|
||||||
if (_biometric)
|
|
||||||
{
|
|
||||||
_biometric = false;
|
|
||||||
}
|
|
||||||
else if (await _platformUtilsService.SupportsBiometricAsync())
|
|
||||||
{
|
|
||||||
_biometric = await _platformUtilsService.AuthenticateBiometricAsync(null,
|
|
||||||
Device.RuntimePlatform == Device.Android ? "." : null);
|
|
||||||
}
|
|
||||||
if (_biometric == current)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_biometric)
|
|
||||||
{
|
|
||||||
await _biometricService.SetupBiometricAsync();
|
|
||||||
await _stateService.SetBiometricUnlockAsync(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _stateService.SetBiometricUnlockAsync(null);
|
|
||||||
}
|
|
||||||
await _stateService.SetBiometricLockedAsync(false);
|
|
||||||
await _cryptoService.ToggleKeyAsync();
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BuildList()
|
|
||||||
{
|
|
||||||
//TODO: Refactor this once navigation is abstracted so that it doesn't depend on Page, e.g. Page.Navigation.PushModalAsync...
|
|
||||||
|
|
||||||
var doUpper = Device.RuntimePlatform != Device.Android;
|
|
||||||
var autofillItems = new List<SettingsPageListItem>();
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
autofillItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.AutofillServices,
|
|
||||||
SubLabel = _autofillHandler.AutofillServicesEnabled() ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillServicesPage(Page as SettingsPage)))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_deviceActionService.SystemMajorVersion() >= 12)
|
|
||||||
{
|
|
||||||
autofillItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.PasswordAutofill,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage()))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
autofillItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.AppExtension,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage()))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var manageItems = new List<SettingsPageListItem>
|
|
||||||
{
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.Folders,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new FoldersPage()))
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.Sync,
|
|
||||||
SubLabel = _lastSyncDate,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new SyncPage()))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var securityItems = new List<SettingsPageListItem>
|
|
||||||
{
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.VaultTimeout,
|
|
||||||
SubLabel = _vaultTimeoutDisplayValue,
|
|
||||||
ExecuteAsync = () => VaultTimeoutAsync() },
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.VaultTimeoutAction,
|
|
||||||
SubLabel = _vaultTimeoutActionDisplayValue,
|
|
||||||
ExecuteAsync = () => VaultTimeoutActionAsync()
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.UnlockWithPIN,
|
|
||||||
SubLabel = _pin ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => UpdatePinAsync()
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.ApproveLoginRequests,
|
|
||||||
SubLabel = _approvePasswordlessLoginRequests ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => ApproveLoginRequestsAsync()
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.LockNow,
|
|
||||||
ExecuteAsync = () => LockAsync()
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.TwoStepLogin,
|
|
||||||
ExecuteAsync = () => TwoStepAsync()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (_approvePasswordlessLoginRequests)
|
|
||||||
{
|
|
||||||
manageItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.PendingLogInRequests,
|
|
||||||
ExecuteAsync = () => PendingLoginRequestsAsync()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (_supportsBiometric || _biometric)
|
|
||||||
{
|
|
||||||
var biometricName = AppResources.Biometrics;
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
biometricName = _deviceActionService.SupportsFaceBiometric() ? AppResources.FaceID :
|
|
||||||
AppResources.TouchID;
|
|
||||||
}
|
|
||||||
var item = new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = string.Format(AppResources.UnlockWith, biometricName),
|
|
||||||
SubLabel = _biometric ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => UpdateBiometricAsync()
|
|
||||||
};
|
|
||||||
securityItems.Insert(2, item);
|
|
||||||
}
|
|
||||||
if (_vaultTimeoutDisplayValue == AppResources.Custom)
|
|
||||||
{
|
|
||||||
securityItems.Insert(1, new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.Custom,
|
|
||||||
Time = TimeSpan.FromMinutes(Math.Abs((double)_vaultTimeout.GetValueOrDefault())),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (_vaultTimeoutPolicy != null)
|
|
||||||
{
|
|
||||||
var policyMinutes = _vaultTimeoutPolicy.GetInt(Policy.MINUTES_KEY);
|
|
||||||
var policyAction = _vaultTimeoutPolicy.GetString(Policy.ACTION_KEY);
|
|
||||||
|
|
||||||
if (policyMinutes.HasValue || !string.IsNullOrWhiteSpace(policyAction))
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
securityItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.AllowScreenCapture,
|
|
||||||
SubLabel = _screenCaptureAllowed ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => SetScreenCaptureAllowedAsync()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var accountItems = new List<SettingsPageListItem>();
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
accountItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.ConnectToWatch,
|
|
||||||
SubLabel = _shouldConnectToWatch ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => ToggleWatchConnectionAsync()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
accountItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.FingerprintPhrase,
|
|
||||||
ExecuteAsync = () => FingerprintAsync()
|
|
||||||
});
|
|
||||||
accountItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.LogOut,
|
|
||||||
ExecuteAsync = () => LogOutAsync()
|
|
||||||
});
|
|
||||||
if (_showChangeMasterPassword)
|
|
||||||
{
|
|
||||||
accountItems.Insert(0, new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.ChangeMasterPassword,
|
|
||||||
ExecuteAsync = () => ChangePasswordAsync()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var toolsItems = new List<SettingsPageListItem>
|
|
||||||
{
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.ImportItems,
|
|
||||||
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Import())
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.ExportVault,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new ExportVaultPage()))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (IncludeLinksWithSubscriptionInfo())
|
|
||||||
{
|
|
||||||
toolsItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.LearnOrg,
|
|
||||||
ExecuteAsync = () => ShareAsync()
|
|
||||||
});
|
|
||||||
toolsItems.Add(new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.WebVault,
|
|
||||||
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => WebVault())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var otherItems = new List<SettingsPageListItem>
|
|
||||||
{
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.Options,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new OptionsPage()))
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.About,
|
|
||||||
ExecuteAsync = () => AboutAsync()
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.HelpAndFeedback,
|
|
||||||
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Help())
|
|
||||||
},
|
|
||||||
#if !FDROID
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.SubmitCrashLogs,
|
|
||||||
SubLabel = _reportLoggingEnabled ? AppResources.On : AppResources.Off,
|
|
||||||
ExecuteAsync = () => LoggerReportingAsync()
|
|
||||||
},
|
|
||||||
#endif
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.RateTheApp,
|
|
||||||
ExecuteAsync = () => Device.InvokeOnMainThreadAsync(() => Rate())
|
|
||||||
},
|
|
||||||
new SettingsPageListItem
|
|
||||||
{
|
|
||||||
Name = AppResources.DeleteAccount,
|
|
||||||
ExecuteAsync = () => Page.Navigation.PushModalAsync(new NavigationPage(new DeleteAccountPage()))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: improve this. Leaving this as is to reduce error possibility on the hotfix.
|
|
||||||
var settingsListGroupItems = new List<SettingsPageListGroup>()
|
|
||||||
{
|
|
||||||
new SettingsPageListGroup(autofillItems, AppResources.Autofill, doUpper, true),
|
|
||||||
new SettingsPageListGroup(manageItems, AppResources.Manage, doUpper),
|
|
||||||
new SettingsPageListGroup(securityItems, AppResources.Security, doUpper),
|
|
||||||
new SettingsPageListGroup(accountItems, AppResources.Account, doUpper),
|
|
||||||
new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper),
|
|
||||||
new SettingsPageListGroup(otherItems, AppResources.Other, doUpper)
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: refactor this
|
|
||||||
if (Device.RuntimePlatform == Device.Android
|
|
||||||
||
|
|
||||||
GroupedItems.Any())
|
|
||||||
{
|
|
||||||
var items = new List<ISettingsPageListItem>();
|
|
||||||
foreach (var itemGroup in settingsListGroupItems)
|
|
||||||
{
|
|
||||||
items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
|
|
||||||
items.AddRange(itemGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupedItems.ReplaceRange(items);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// HACK: we need this on iOS, so that it doesn't crash when adding coming from an empty list
|
|
||||||
var first = true;
|
|
||||||
var items = new List<ISettingsPageListItem>();
|
|
||||||
foreach (var itemGroup in settingsListGroupItems)
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
{
|
|
||||||
items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
items.AddRange(itemGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (settingsListGroupItems.Any())
|
|
||||||
{
|
|
||||||
GroupedItems.ReplaceRange(new List<ISettingsPageListItem> { new SettingsPageHeaderListItem(settingsListGroupItems[0].Name) });
|
|
||||||
GroupedItems.AddRange(items);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GroupedItems.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PendingLoginRequestsAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var requests = await _authService.GetActivePasswordlessLoginRequestsAsync();
|
|
||||||
if (requests == null || !requests.Any())
|
|
||||||
{
|
|
||||||
_platformUtilsService.ShowToast("info", null, AppResources.NoPendingRequests);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Page.Navigation.PushModalAsync(new NavigationPage(new LoginPasswordlessRequestsListPage())).FireAndForget();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
HandleException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IncludeLinksWithSubscriptionInfo()
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private VaultTimeoutAction GetVaultTimeoutActionFromKey(string key)
|
|
||||||
{
|
|
||||||
return _vaultTimeoutActionOptions.FirstOrDefault(o => o.Key == key).Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int? GetVaultTimeoutFromKey(string key)
|
|
||||||
{
|
|
||||||
return _vaultTimeoutOptions.FirstOrDefault(o => o.Key == key).Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string CreateSelectableOption(string option, bool selected) => selected ? $"✓ {option}" : option;
|
|
||||||
|
|
||||||
private bool CompareSelection(string selection, string compareTo) => selection == compareTo || selection == $"✓ {compareTo}";
|
|
||||||
|
|
||||||
public async Task SetScreenCaptureAllowedAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!_screenCaptureAllowed
|
|
||||||
&&
|
|
||||||
!await Page.DisplayAlert(AppResources.AllowScreenCapture, AppResources.AreYouSureYouWantToEnableScreenCapture, AppResources.Yes, AppResources.No))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _stateService.SetScreenCaptureAllowedAsync(!_screenCaptureAllowed);
|
|
||||||
_screenCaptureAllowed = !_screenCaptureAllowed;
|
|
||||||
await _deviceActionService.SetScreenCaptureAllowedAsync();
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_loggerService.Exception(ex);
|
|
||||||
await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.GenericErrorMessage, AppResources.Ok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ToggleWatchConnectionAsync()
|
|
||||||
{
|
|
||||||
_shouldConnectToWatch = !_shouldConnectToWatch;
|
|
||||||
|
|
||||||
await _watchDeviceService.SetShouldConnectToWatchAsync(_shouldConnectToWatch);
|
|
||||||
BuildList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.SyncPage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:SyncPageViewModel"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:SyncPageViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ContentPage.ToolbarItems>
|
|
||||||
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
|
|
||||||
</ContentPage.ToolbarItems>
|
|
||||||
|
|
||||||
<ScrollView Padding="0, 0, 0, 20">
|
|
||||||
<StackLayout Padding="0" Spacing="20">
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<StackLayout StyleClass="box-row, box-row-switch">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n EnableSyncOnRefresh}"
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
HorizontalOptions="StartAndExpand" />
|
|
||||||
<Switch
|
|
||||||
IsToggled="{Binding EnableSyncOnRefresh}"
|
|
||||||
StyleClass="box-value"
|
|
||||||
HorizontalOptions="End" />
|
|
||||||
</StackLayout>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n EnableSyncOnRefreshDescription}"
|
|
||||||
StyleClass="box-footer-label, box-footer-label-switch" />
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout StyleClass="box">
|
|
||||||
<Button Text="{u:I18n SyncVaultNow}" Clicked="Sync_Clicked"></Button>
|
|
||||||
<Label StyleClass="text-muted, text-sm" HorizontalTextAlignment="Center" Margin="0,10">
|
|
||||||
<Label.FormattedText>
|
|
||||||
<FormattedString>
|
|
||||||
<Span Text="{u:I18n LastSync}" />
|
|
||||||
<Span Text=" " />
|
|
||||||
<Span Text="{Binding LastSync}" />
|
|
||||||
</FormattedString>
|
|
||||||
</Label.FormattedText>
|
|
||||||
</Label>
|
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public partial class SyncPage : BaseContentPage
|
|
||||||
{
|
|
||||||
private readonly SyncPageViewModel _vm;
|
|
||||||
|
|
||||||
public SyncPage()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
_vm = BindingContext as SyncPageViewModel;
|
|
||||||
_vm.Page = this;
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
ToolbarItems.RemoveAt(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
|
||||||
{
|
|
||||||
base.OnAppearing();
|
|
||||||
await _vm.InitAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Sync_Clicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
if (DoOnce())
|
|
||||||
{
|
|
||||||
await _vm.SyncAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void Close_Clicked(object sender, System.EventArgs e)
|
|
||||||
{
|
|
||||||
if (DoOnce())
|
|
||||||
{
|
|
||||||
await Navigation.PopModalAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Exceptions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class SyncPageViewModel : BaseViewModel
|
|
||||||
{
|
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly IStateService _stateService;
|
|
||||||
private readonly ISyncService _syncService;
|
|
||||||
private readonly ILocalizeService _localizeService;
|
|
||||||
|
|
||||||
private string _lastSync = "--";
|
|
||||||
private bool _inited;
|
|
||||||
private bool _syncOnRefresh;
|
|
||||||
|
|
||||||
public SyncPageViewModel()
|
|
||||||
{
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
|
||||||
_localizeService = ServiceContainer.Resolve<ILocalizeService>("localizeService");
|
|
||||||
|
|
||||||
PageTitle = AppResources.Sync;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnableSyncOnRefresh
|
|
||||||
{
|
|
||||||
get => _syncOnRefresh;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (SetProperty(ref _syncOnRefresh, value))
|
|
||||||
{
|
|
||||||
var task = UpdateSyncOnRefreshAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string LastSync
|
|
||||||
{
|
|
||||||
get => _lastSync;
|
|
||||||
set => SetProperty(ref _lastSync, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InitAsync()
|
|
||||||
{
|
|
||||||
await SetLastSyncAsync();
|
|
||||||
EnableSyncOnRefresh = await _stateService.GetSyncOnRefreshAsync();
|
|
||||||
_inited = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateSyncOnRefreshAsync()
|
|
||||||
{
|
|
||||||
if (_inited)
|
|
||||||
{
|
|
||||||
await _stateService.SetSyncOnRefreshAsync(_syncOnRefresh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetLastSyncAsync()
|
|
||||||
{
|
|
||||||
var last = await _syncService.GetLastSyncAsync();
|
|
||||||
if (last != null)
|
|
||||||
{
|
|
||||||
var localDate = last.Value.ToLocalTime();
|
|
||||||
LastSync = string.Format("{0} {1}",
|
|
||||||
_localizeService.GetLocaleShortDate(localDate),
|
|
||||||
_localizeService.GetLocaleShortTime(localDate));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LastSync = AppResources.Never;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SyncAsync()
|
|
||||||
{
|
|
||||||
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
|
|
||||||
AppResources.InternetConnectionRequiredTitle);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _deviceActionService.ShowLoadingAsync(AppResources.Syncing);
|
|
||||||
await _syncService.SyncPasswordlessLoginRequestsAsync();
|
|
||||||
var success = await _syncService.FullSyncAsync(true);
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
await SetLastSyncAsync();
|
|
||||||
_platformUtilsService.ShowToast("success", null, AppResources.SyncingComplete);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Page.DisplayAlert(null, AppResources.SyncingFailed, AppResources.Ok);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ApiException e)
|
|
||||||
{
|
|
||||||
await _deviceActionService.HideLoadingAsync();
|
|
||||||
if (e?.Error != null)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(),
|
|
||||||
AppResources.AnErrorHasOccurred);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ using Android.Views;
|
|||||||
using System;
|
using System;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.Droid.Utilities;
|
using Bit.App.Droid.Utilities;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@@ -10,8 +10,13 @@ using Android.Runtime;
|
|||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Bit.App.Resources;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Application = Android.App.Application;
|
||||||
|
using View = Android.Views.View;
|
||||||
|
using Resource = Bit.Core.Resource;
|
||||||
|
using Point = Android.Graphics.Point;
|
||||||
|
using Rect = Android.Graphics.Rect;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@@ -704,7 +709,7 @@ namespace Bit.Droid.Accessibility
|
|||||||
public static LinearLayout GetOverlayView(Context context)
|
public static LinearLayout GetOverlayView(Context context)
|
||||||
{
|
{
|
||||||
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
||||||
var view = (LinearLayout)inflater.Inflate(Resource.Layout.autofill_listitem, null);
|
var view = (LinearLayout)inflater.Inflate(Bit.Core.Resource.Layout.autofill_listitem, null);
|
||||||
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
||||||
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
||||||
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
||||||
@@ -9,9 +9,10 @@ using Android.Runtime;
|
|||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Bit.App.Resources;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using View = Android.Views.View;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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.4.1" 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.10.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
<uses-permission android:name="android.permission.NFC" />
|
||||||
@@ -4,14 +4,14 @@ using Android.Content.PM;
|
|||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.Droid.Utilities;
|
using Bit.App.Droid.Utilities;
|
||||||
|
|
||||||
namespace Bit.Droid.Autofill
|
namespace Bit.Droid.Autofill
|
||||||
{
|
{
|
||||||
[Activity(
|
[Activity(
|
||||||
NoHistory = true,
|
NoHistory = true,
|
||||||
LaunchMode = LaunchMode.SingleTop)]
|
LaunchMode = LaunchMode.SingleTop)]
|
||||||
public class AutofillExternalSelectionActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
public class AutofillExternalSelectionActivity : MauiAppCompatActivity
|
||||||
{
|
{
|
||||||
protected override void OnCreate(Bundle bundle)
|
protected override void OnCreate(Bundle bundle)
|
||||||
{
|
{
|
||||||
@@ -12,14 +12,17 @@ using Android.Graphics.Drawables;
|
|||||||
using Android.OS;
|
using Android.OS;
|
||||||
using Android.Runtime;
|
using Android.Runtime;
|
||||||
using Android.Widget.Inline;
|
using Android.Widget.Inline;
|
||||||
using Bit.App.Resources;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Android.Views.Autofill;
|
using Android.Views.Autofill;
|
||||||
using AndroidX.AutoFill.Inline;
|
using AndroidX.AutoFill.Inline;
|
||||||
using AndroidX.AutoFill.Inline.V1;
|
using AndroidX.AutoFill.Inline.V1;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using SaveFlags = Android.Service.Autofill.SaveFlags;
|
using SaveFlags = Android.Service.Autofill.SaveFlags;
|
||||||
using Bit.Droid.Utilities;
|
using Bit.App.Droid.Utilities;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Resource = Bit.Core.Resource;
|
||||||
|
using BlendMode = Android.Graphics.BlendMode;
|
||||||
|
|
||||||
namespace Bit.Droid.Autofill
|
namespace Bit.Droid.Autofill
|
||||||
{
|
{
|
||||||
@@ -152,8 +155,9 @@ namespace Bit.Droid.Autofill
|
|||||||
"androidapp://com.oneplus.applocker",
|
"androidapp://com.oneplus.applocker",
|
||||||
};
|
};
|
||||||
|
|
||||||
public static async Task<List<FilledItem>> GetFillItemsAsync(Parser parser, ICipherService cipherService)
|
public static async Task<List<FilledItem>> GetFillItemsAsync(Parser parser, ICipherService cipherService, IUserVerificationService userVerificationService)
|
||||||
{
|
{
|
||||||
|
var userHasMasterPassword = await userVerificationService.HasMasterPasswordAsync();
|
||||||
if (parser.FieldCollection.FillableForLogin)
|
if (parser.FieldCollection.FillableForLogin)
|
||||||
{
|
{
|
||||||
var ciphers = await cipherService.GetAllDecryptedByUrlAsync(parser.Uri);
|
var ciphers = await cipherService.GetAllDecryptedByUrlAsync(parser.Uri);
|
||||||
@@ -161,14 +165,14 @@ namespace Bit.Droid.Autofill
|
|||||||
{
|
{
|
||||||
var allCiphers = ciphers.Item1.ToList();
|
var allCiphers = ciphers.Item1.ToList();
|
||||||
allCiphers.AddRange(ciphers.Item2.ToList());
|
allCiphers.AddRange(ciphers.Item2.ToList());
|
||||||
var nonPromptCiphers = allCiphers.Where(cipher => cipher.Reprompt == CipherRepromptType.None);
|
var nonPromptCiphers = allCiphers.Where(cipher => !userHasMasterPassword || cipher.Reprompt == CipherRepromptType.None);
|
||||||
return nonPromptCiphers.Select(c => new FilledItem(c)).ToList();
|
return nonPromptCiphers.Select(c => new FilledItem(c)).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parser.FieldCollection.FillableForCard)
|
else if (parser.FieldCollection.FillableForCard)
|
||||||
{
|
{
|
||||||
var ciphers = await cipherService.GetAllDecryptedAsync();
|
var ciphers = await cipherService.GetAllDecryptedAsync();
|
||||||
return ciphers.Where(c => c.Type == CipherType.Card && c.Reprompt == CipherRepromptType.None).Select(c => new FilledItem(c)).ToList();
|
return ciphers.Where(c => c.Type == CipherType.Card && (!userHasMasterPassword || c.Reprompt == CipherRepromptType.None)).Select(c => new FilledItem(c)).ToList();
|
||||||
}
|
}
|
||||||
return new List<FilledItem>();
|
return new List<FilledItem>();
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ using Android.Widget;
|
|||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
namespace Bit.Droid.Autofill
|
namespace Bit.Droid.Autofill
|
||||||
@@ -26,6 +27,7 @@ namespace Bit.Droid.Autofill
|
|||||||
private IPolicyService _policyService;
|
private IPolicyService _policyService;
|
||||||
private IStateService _stateService;
|
private IStateService _stateService;
|
||||||
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
||||||
|
private IUserVerificationService _userVerificationService;
|
||||||
|
|
||||||
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
|
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
|
||||||
FillCallback callback)
|
FillCallback callback)
|
||||||
@@ -64,11 +66,9 @@ namespace Bit.Droid.Autofill
|
|||||||
var locked = await _vaultTimeoutService.IsLockedAsync();
|
var locked = await _vaultTimeoutService.IsLockedAsync();
|
||||||
if (!locked)
|
if (!locked)
|
||||||
{
|
{
|
||||||
if (_cipherService == null)
|
_cipherService ??= ServiceContainer.Resolve<ICipherService>();
|
||||||
{
|
_userVerificationService ??= ServiceContainer.Resolve<IUserVerificationService>();
|
||||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService, _userVerificationService);
|
||||||
}
|
|
||||||
items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// build response
|
// build response
|
||||||
@@ -6,6 +6,7 @@ using Android.Views.Autofill;
|
|||||||
using static Android.App.Assist.AssistStructure;
|
using static Android.App.Assist.AssistStructure;
|
||||||
using Android.Text;
|
using Android.Text;
|
||||||
using static Android.Views.ViewStructure;
|
using static Android.Views.ViewStructure;
|
||||||
|
using View = Android.Views.View;
|
||||||
|
|
||||||
namespace Bit.Droid.Autofill
|
namespace Bit.Droid.Autofill
|
||||||
{
|
{
|
||||||
@@ -4,6 +4,7 @@ using Android.Views.Autofill;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Android.Text;
|
using Android.Text;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
|
using View = Android.Views.View;
|
||||||
|
|
||||||
namespace Bit.Droid.Autofill
|
namespace Bit.Droid.Autofill
|
||||||
{
|
{
|
||||||
@@ -12,7 +13,7 @@ namespace Bit.Droid.Autofill
|
|||||||
private List<Field> _passwordFields = null;
|
private List<Field> _passwordFields = null;
|
||||||
private List<Field> _usernameFields = null;
|
private List<Field> _usernameFields = null;
|
||||||
private HashSet<string> _ignoreSearchTerms = new HashSet<string> { "search", "find", "recipient", "edit" };
|
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" };
|
private HashSet<string> _passwordTerms = new HashSet<string> { "password", "pswd" };
|
||||||
|
|
||||||
public List<AutofillId> AutofillIds { get; private set; } = new List<AutofillId>();
|
public List<AutofillId> AutofillIds { get; private set; } = new List<AutofillId>();
|
||||||
@@ -54,15 +55,14 @@ namespace Bit.Droid.Autofill
|
|||||||
if (HintToFieldsMap.ContainsKey(View.AutofillHintPassword))
|
if (HintToFieldsMap.ContainsKey(View.AutofillHintPassword))
|
||||||
{
|
{
|
||||||
_passwordFields.AddRange(HintToFieldsMap[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();
|
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
|
||||||
if (!_passwordFields.Any())
|
|
||||||
{
|
|
||||||
_passwordFields = Fields.Where(f => FieldHasPasswordTerms(f)).ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return _passwordFields;
|
return _passwordFields;
|
||||||
}
|
}
|
||||||
@@ -87,24 +87,26 @@ namespace Bit.Droid.Autofill
|
|||||||
{
|
{
|
||||||
_usernameFields.AddRange(HintToFieldsMap[View.AutofillHintUsername]);
|
_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;
|
return _usernameFields;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Bit.Core.Models.View;
|
using Bit.Core.Models.View;
|
||||||
|
using Resource = Bit.Core.Resource;
|
||||||
|
|
||||||
namespace Bit.Droid.Autofill
|
namespace Bit.Droid.Autofill
|
||||||
{
|
{
|
||||||
13
src/App/Platforms/Android/Constants.cs
Normal file
13
src/App/Platforms/Android/Constants.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace Bit.Droid
|
||||||
|
{
|
||||||
|
public static class Constants
|
||||||
|
{
|
||||||
|
public const string PACKAGE_NAME = "com.x8bit.bitwarden";
|
||||||
|
public const string TEMP_CAMERA_IMAGE_NAME = "temp_camera_image.jpg";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This directory must also be declared in filepaths.xml
|
||||||
|
/// </summary>
|
||||||
|
public const string TEMP_CAMERA_IMAGE_DIR = "camera_temp";
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user