1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-05 23:53:33 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
fe1067bedf Bump async from 2.6.3 to 2.6.4
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-23 16:25:15 +00:00
928 changed files with 213766 additions and 15036 deletions

7
.github/CODEOWNERS vendored
View File

@@ -10,13 +10,6 @@
# DevOps for Actions and other workflow changes # DevOps for Actions and other workflow changes
.github/workflows @bitwarden/dept-devops .github/workflows @bitwarden/dept-devops
# DevOps for Version Bumping
src/App/Platforms/Android/AndroidManifest.xml
src/iOS.Autofill/Info.plist
src/iOS.Extension/Info.plist
src/iOS.ShareExtension/Info.plist
src/App/Platforms/iOS/Info.plist
## Auth team files ## ## Auth team files ##
## Platform team files ## ## Platform team files ##

View File

@@ -2,7 +2,6 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [ "extends": [
"config:base", "config:base",
"github>bitwarden/renovate-config:pin-actions",
":combinePatchMinorReleases", ":combinePatchMinorReleases",
":dependencyDashboard", ":dependencyDashboard",
":maintainLockFilesWeekly", ":maintainLockFilesWeekly",

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,3 @@
<EFBFBD>
 K<>Y#<23>(<28><><EFBFBD><EFBFBD>EI֐߄T?)l<><6C><EFBFBD><18><><10>"=<3D>|<7C>'e<><0E>m<EFBFBD>/~<7E><>' F<><46>><3E><><EFBFBD><EFBFBD>l<EFBFBD>b<EFBFBD>[<5B>+R<><52>iL<69><4C>"<22><><EFBFBD>~V:<3A><>p<EFBFBD>a<17>ڵel%8t<38><74><EFBFBD>y<<3C>n<EFBFBD><6E><EFBFBD>aU<61>w<16>JD<4A><44><1F><>We<57>9<EFBFBD><39><EFBFBD><EFBFBD><x8d<38>O<EFBFBD>j\<14>ד<EFBFBD><D793><EFBFBD>Vq<56><71>֋
Ǻ<EFBFBD>-<2D>#<23><><11><>]$<24>(<28>l,<2C>Br<42><02><>d<><64><EFBFBD>•a-<2D><><EFBFBD>:<3A><>:<3A><04>9b,!Em<02><19><>Qf<>D<EFBFBD>g<EFBFBD><06><0E>x(P<>ȡ~<7E>͹<EFBFBD><CDB9> <09><>[<06><>!:<3A>;f<><66>

Binary file not shown.

BIN
.github/secrets/play_creds.json.gpg vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +0,0 @@
---
name: Build Beta
on:
workflow_dispatch:

View File

@@ -10,11 +10,6 @@ on:
- ".github/workflows/**" - ".github/workflows/**"
workflow_dispatch: workflow_dispatch:
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
@@ -68,27 +63,19 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
variant: ["prod", "qa"] variant: ["prod", "qa"]
env:
android_folder_path: src\App\Platforms\Android
android_folder_path_bash: 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: 6.4.0 nuget-version: 5.9.0
- name: Set up .NET - name: Set up .NET
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0 uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
with: with:
dotnet-version: '8.0.x' dotnet-version: '3.1.x'
- name: Set up MSBuild - name: Set up MSBuild
uses: microsoft/setup-msbuild@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3 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
@@ -96,8 +83,7 @@ jobs:
- name: Install Microsoft OpenJDK 11 - name: Install Microsoft OpenJDK 11
run: | run: |
choco install microsoft-openjdk11 --no-progress choco install microsoft-openjdk11 --no-progress
Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | ` Write-Output "JAVA_HOME=$(Get-ChildItem -Path 'C:\Program Files\Microsoft\jdk*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Write-Output "Java Home: $env:JAVA_HOME" Write-Output "Java Home: $env:JAVA_HOME"
- name: Print environment - name: Print environment
@@ -113,34 +99,27 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Login to Azure - CI Subscription - name: Decrypt secrets
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Download secrets
env: env:
ACCOUNT_NAME: bitwardenci DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
CONTAINER_NAME: mobile
run: | run: |
mkdir -p $HOME/secrets mkdir -p ~/secrets
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--name app_play-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_play-keystore.jks --output none --output ./src/Android/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--name app_upload-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_upload-keystore.jks --output none --output ./src/Android/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--name play_creds.json --file $HOME/secrets/play_creds.json --output none --output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg
shell: bash shell: bash
- name: Download secrets - Google Services - name: Decrypt secrets - Google Services
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
env: env:
ACCOUNT_NAME: bitwardenci DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
CONTAINER_NAME: mobile
run: | run: |
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--name google-services.json --file ./${{ env.android_folder_path_bash }}/google-services.json --output none --output ./src/Android/google-services.json ./.github/secrets/google-services.json.gpg
shell: bash shell: bash
- name: Increment version - name: Increment version
@@ -152,7 +131,7 @@ jobs:
echo "########################################" echo "########################################"
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
./${{ env.android_folder_path_bash }}/AndroidManifest.xml ./src/Android/Properties/AndroidManifest.xml
shell: bash shell: bash
- name: Restore packages - name: Restore packages
@@ -161,75 +140,87 @@ jobs:
- name: Restore tools - name: Restore tools
run: dotnet tool restore run: dotnet tool restore
# - name: Run Core tests - name: Verify Format
# run: | run: dotnet tool run dotnet-format --check
# dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx" `
# /p:CustomConstants=UT
# - name: Report test results - name: Run Core tests
# uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0 run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx"
# if: always()
# with: - name: Report test results
# name: Test Results uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
# path: "**/test-results.trx" if: always()
# reporter: dotnet-trx with:
# fail-on-error: true name: Test Results
path: "**/test-results.trx"
reporter: dotnet-trx
fail-on-error: true
- name: Build Play Store publisher - name: Build Play Store publisher
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
run: dotnet build .\store\google\Publisher\Publisher.csproj /p:Configuration=Release run: dotnet build ./store/google/Publisher/Publisher.csproj -p:Configuration=Release
- name: Setup Android build (${{ matrix.variant }}) - name: Setup Android build (${{ matrix.variant }})
run: dotnet cake build.cake --target Android --variant ${{ matrix.variant }} run: dotnet cake build.cake --target Android --variant ${{ matrix.variant }}
- name: Build & Sign Android - name: Build Android
run: |
$configuration = "Release";
Write-Output "########################################"
Write-Output "##### Build $configuration Configuration"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
- name: Sign Android Build
env: env:
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: |
$projToBuild = "$($env:GITHUB_WORKSPACE)/${{ env.main_app_project_path }}"; $androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
$packageName = "com.x8bit.bitwarden"; $packageName = "com.x8bit.bitwarden";
if ("${{ matrix.variant }}" -ne "prod") if ("${{ matrix.variant }}" -ne "prod")
{ {
$packageName = "com.x8bit.bitwarden.${{ matrix.variant }}"; $packageName = "com.x8bit.bitwarden.${{ matrix.variant }}";
} }
Write-Output "########################################"
Write-Output "##### Sign Google Play Bundle Release Configuration" Write-Output "##### Sign Google Play Bundle Release Configuration"
Write-Output "########################################"
$signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_upload-keystore.jks" msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android ` "/p:AndroidSigningKeyAlias=upload" "/p:AndroidSigningKeyPass=$($env:UPLOAD_KEYSTORE_PASSWORD)" `
/p:AndroidPackageFormats=aab ` "/p:AndroidSigningKeyStore=$("app_upload-keystore.jks")" `
/p:AndroidKeyStore=true ` "/p:AndroidSigningStorePass=$($env:UPLOAD_KEYSTORE_PASSWORD)" "/p:AndroidPackageFormat=aab" "/v:quiet"
/p:AndroidSigningKeyStore=$signingUploadKeyStore `
/p:AndroidSigningKeyAlias=upload `
/p:AndroidSigningKeyPass="$($env:UPLOAD_KEYSTORE_PASSWORD)" `
/p:AndroidSigningStorePass="$($env:UPLOAD_KEYSTORE_PASSWORD)" --no-restore
Write-Output "########################################"
Write-Output "##### Copy Google Play Bundle to project root" Write-Output "##### Copy Google Play Bundle to project root"
Write-Output "########################################"
$signedAabPath = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_folder_path }}\bin\Release\${{ env.target-net-version }}-android\publish\$($packageName)-Signed.aab"; $signedAabPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/Release/$($packageName)-Signed.aab");
$signedAabDestPath = "$($env:GITHUB_WORKSPACE)\$($packageName).aab"; $signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab");
Copy-Item $signedAabPath $signedAabDestPath Copy-Item $signedAabPath $signedAabDestPath
Write-Output "########################################"
Write-Output "##### Sign APK Release Configuration" Write-Output "##### Sign APK Release Configuration"
Write-Output "########################################"
$signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_play-keystore.jks" msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android ` "/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:PLAY_KEYSTORE_PASSWORD)" `
/p:AndroidKeyStore=true ` "/p:AndroidSigningKeyStore=$("app_play-keystore.jks")" `
/p:AndroidSigningKeyStore=$signingPlayKeyStore ` "/p:AndroidSigningStorePass=$($env:PLAY_KEYSTORE_PASSWORD)" "/v:quiet"
/p:AndroidSigningKeyAlias=bitwarden `
/p:AndroidSigningKeyPass="$($env:PLAY_KEYSTORE_PASSWORD)" `
/p:AndroidSigningStorePass="$($env:PLAY_KEYSTORE_PASSWORD)" --no-restore
Write-Output "########################################"
Write-Output "##### Copy Release APK to project root" Write-Output "##### Copy Release APK to project root"
Write-Output "########################################"
$signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/Release/$($packageName)-Signed.apk");
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).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";
Copy-Item $signedApkPath $signedApkDestPath Copy-Item $signedApkPath $signedApkDestPath
- name: Upload Prod .aab artifact - name: Upload Prod .aab artifact
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: com.x8bit.bitwarden.aab name: com.x8bit.bitwarden.aab
path: ./com.x8bit.bitwarden.aab path: ./com.x8bit.bitwarden.aab
@@ -237,7 +228,7 @@ jobs:
- name: Upload Prod .apk artifact - name: Upload Prod .apk artifact
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: com.x8bit.bitwarden.apk name: com.x8bit.bitwarden.apk
path: ./com.x8bit.bitwarden.apk path: ./com.x8bit.bitwarden.apk
@@ -245,7 +236,7 @@ jobs:
- name: Upload Other .apk artifact - name: Upload Other .apk artifact
if: ${{ matrix.variant != 'prod' }} if: ${{ matrix.variant != 'prod' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: com.x8bit.bitwarden.${{ matrix.variant }}.apk name: com.x8bit.bitwarden.${{ matrix.variant }}.apk
path: ./com.x8bit.bitwarden.${{ matrix.variant }}.apk path: ./com.x8bit.bitwarden.${{ matrix.variant }}.apk
@@ -265,7 +256,7 @@ jobs:
- name: Upload .apk sha file for prod - name: Upload .apk sha file for prod
if: ${{ matrix.variant == 'prod' }} if: ${{ matrix.variant == 'prod' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: bw-android-apk-sha256.txt name: bw-android-apk-sha256.txt
path: ./bw-android-apk-sha256.txt path: ./bw-android-apk-sha256.txt
@@ -273,7 +264,7 @@ jobs:
- name: Upload .apk sha file for other - name: Upload .apk sha file for other
if: ${{ matrix.variant != 'prod' }} if: ${{ matrix.variant != 'prod' }}
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: bw-android-${{ matrix.variant }}-apk-sha256.txt name: bw-android-${{ matrix.variant }}-apk-sha256.txt
path: ./bw-android-${{ matrix.variant }}-apk-sha256.txt path: ./bw-android-${{ matrix.variant }}-apk-sha256.txt
@@ -286,38 +277,26 @@ jobs:
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) || (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc' ) }} || github.ref == 'refs/heads/hotfix-rc' ) }}
run: | run: |
$publisherPath = "$($env:GITHUB_WORKSPACE)\store\google\Publisher\bin\Release\net8.0\Publisher.dll" PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/netcoreapp3.1/Publisher.dll"
$credsPath = "$($HOME)\secrets\play_creds.json" CREDS_PATH="$HOME/secrets/play_creds.json"
$aabPath = "$($env:GITHUB_WORKSPACE)\com.x8bit.bitwarden.aab" AAB_PATH="$GITHUB_WORKSPACE/com.x8bit.bitwarden.aab"
$track = "internal" TRACK="internal"
dotnet $publisherPath $credsPath $aabPath $track dotnet $PUBLISHER_PATH $CREDS_PATH $AAB_PATH $TRACK
shell: bash
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: 6.4.0 nuget-version: 5.9.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@ede762b26a2de8d110bb5a3db4d7e0e080c0e917 # v1.3.3 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
@@ -339,44 +318,54 @@ jobs:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Login to Azure - CI Subscription - name: Decrypt secrets
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Download secrets
env: env:
ACCOUNT_NAME: bitwardenci DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
CONTAINER_NAME: mobile
FILE: app_fdroid-keystore.jks
run: | run: |
mkdir -p $HOME/secrets mkdir -p ~/secrets
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
--file $HOME/secrets/$FILE --output none gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/Android/app_fdroid-keystore.jks ./.github/secrets/app_fdroid-keystore.jks.gpg
shell: bash shell: bash
- name: Increment version - name: Increment version
run: | run: |
BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER)) BUILD_NUMBER=$((3000 + $GITHUB_RUN_NUMBER))
echo "########################################"
echo "##### Setting Version Code $BUILD_NUMBER" echo "##### Setting Version Code $BUILD_NUMBER"
echo "########################################"
sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \ sed -i "s/android:versionCode=\"1\"/android:versionCode=\"$BUILD_NUMBER\"/" \
./${{ env.android_manifest_path }} ./src/Android/Properties/AndroidManifest.xml
shell: bash shell: bash
- name: Clean for F-Droid - name: Clean for F-Droid
run: | run: |
$appPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}"); $androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
$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 + "/${{ env.android_manifest_path }}"); $androidManifest = $($env:GITHUB_WORKSPACE + "/src/Android/Properties/AndroidManifest.xml");
Write-Output "##### Back up project files" Write-Output "########################################"
Write-Output "##### Clean Android and App"
Write-Output "########################################"
msbuild "$($androidPath)" "/t:Clean" "/p:Configuration=FDroid"
msbuild "$($appPath)" "/t:Clean" "/p:Configuration=FDroid"
Write-Output "########################################"
Write-Output "##### Backup project files"
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 "##### Cleanup Android Manifest" Write-Output "##### Cleanup Android Manifest"
Write-Output "########################################"
$xml=New-Object XML; $xml=New-Object XML;
$xml.Load($androidManifest); $xml.Load($androidManifest);
@@ -386,38 +375,80 @@ jobs:
$xml.Save($androidManifest); $xml.Save($androidManifest);
Write-Output "########################################"
Write-Output "##### Uninstall from Android.csproj"
Write-Output "########################################"
$xml=New-Object XML;
$xml.Load($androidPath);
$ns=New-Object System.Xml.XmlNamespaceManager($xml.NameTable);
$ns.AddNamespace("ns", $xml.DocumentElement.NamespaceURI);
$firebaseNode=$xml.SelectSingleNode(`
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Firebase.Messaging']", $ns);
$firebaseNode.ParentNode.RemoveChild($firebaseNode);
$daggerNode=$xml.SelectSingleNode(`
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.Google.Dagger']", $ns);
$daggerNode.ParentNode.RemoveChild($daggerNode);
$safetyNetNode=$xml.SelectSingleNode(`
"/ns:Project/ns:ItemGroup/ns:PackageReference[@Include='Xamarin.GooglePlayServices.SafetyNet']", $ns);
$safetyNetNode.ParentNode.RemoveChild($safetyNetNode);
$xml.Save($androidPath);
Write-Output "########################################"
Write-Output "##### Uninstall from Core.csproj"
Write-Output "########################################"
$xml=New-Object XML;
$xml.Load($corePath);
$appCenterNode=$xml.SelectSingleNode("/Project/ItemGroup/PackageReference[@Include='Microsoft.AppCenter.Crashes']");
$appCenterNode.ParentNode.RemoveChild($appCenterNode);
$xml.Save($corePath);
- name: Restore packages - name: Restore packages
run: dotnet restore run: nuget restore
- name: Build for F-Droid - name: Build for F-Droid
run: | run: |
$configuration = "Release"; $configuration = "FDroid";
$projToBuild = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_project_path }}");
Write-Output "##### Build $configuration FDROID" Write-Output "########################################"
Write-Output "##### Build $configuration Configuration"
Write-Output "########################################"
dotnet build $projToBuild -c $configuration -f ${{ env.target-net-version }}-android /p:CustomConstants="FDROID" msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
- 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 }}"); Write-Output "########################################"
$packageName = "com.x8bit.bitwarden"; Write-Output "##### Sign FDroid Configuration"
Write-Output "########################################"
Write-Output "##### Sign FDroid" msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" `
"/t:SignAndroidPackage" "/p:Configuration=FDroid" "/p:AndroidKeyStore=true" `
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 "/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 "##### Copy FDroid apk to project root" Write-Output "##### Copy FDroid apk to project root"
Write-Output "########################################"
$signedApkPath = $($env:GITHUB_WORKSPACE + "/${{ env.main_app_folder_path }}/bin/Release/${{ env.target-net-version }}-android/publish/$($packageName)-Signed.apk"); $signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/FDroid/com.x8bit.bitwarden-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
- name: Upload F-Droid .apk artifact - name: Upload F-Droid .apk artifact
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: com.x8bit.bitwarden-fdroid.apk name: com.x8bit.bitwarden-fdroid.apk
path: ./com.x8bit.bitwarden-fdroid.apk path: ./com.x8bit.bitwarden-fdroid.apk
@@ -429,7 +460,7 @@ jobs:
-t sha256 | Out-File -Encoding ASCII ./bw-fdroid-apk-sha256.txt -t sha256 | Out-File -Encoding ASCII ./bw-fdroid-apk-sha256.txt
- name: Upload F-Droid sha file - name: Upload F-Droid sha file
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: bw-fdroid-apk-sha256.txt name: bw-fdroid-apk-sha256.txt
path: ./bw-fdroid-apk-sha256.txt path: ./bw-fdroid-apk-sha256.txt
@@ -438,36 +469,18 @@ jobs:
ios: ios:
name: Apple iOS name: Apple iOS
runs-on: macos-13 runs-on: macos-12
needs: setup needs: setup
env:
ios_folder_path: src/App/Platforms/iOS
app_output_name: App
app_ci_output_filename: App_x64_Debug
steps: steps:
- name: Set XCode version
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
with:
xcode-version: 15.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: 6.4.0 nuget-version: 5.9.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"
@@ -478,7 +491,7 @@ jobs:
submodules: 'true' submodules: 'true'
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
with: with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
@@ -489,73 +502,71 @@ jobs:
keyvault: "bitwarden-ci" keyvault: "bitwarden-ci"
secrets: "appcenter-ios-token" secrets: "appcenter-ios-token"
- name: Download Provisioning Profiles secrets - name: Decrypt secrets
env: env:
ACCOUNT_NAME: bitwardenci DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
CONTAINER_NAME: profiles
run: | run: |
mkdir -p $HOME/secrets mkdir -p ~/secrets
profiles=(
"dist_autofill.mobileprovision"
"dist_bitwarden.mobileprovision"
"dist_extension.mobileprovision"
"dist_share_extension.mobileprovision"
"dist_bitwarden_watch_app.mobileprovision"
"dist_bitwarden_watch_app_extension.mobileprovision"
)
for FILE in "${profiles[@]}" gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
do --output $HOME/secrets/bitwarden-mobile-key.p12 ./.github/secrets/bitwarden-mobile-key.p12.gpg
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--file $HOME/secrets/$FILE --output none --output $HOME/secrets/iphone-distribution-cert.p12 ./.github/secrets/iphone-distribution-cert.p12.gpg
done gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output $HOME/secrets/dist_autofill.mobileprovision ./.github/secrets/dist_autofill.mobileprovision.gpg
- name: Download Google Services secret gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
env: --output $HOME/secrets/dist_bitwarden.mobileprovision ./.github/secrets/dist_bitwarden.mobileprovision.gpg
ACCOUNT_NAME: bitwardenci gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
CONTAINER_NAME: mobile --output $HOME/secrets/dist_extension.mobileprovision ./.github/secrets/dist_extension.mobileprovision.gpg
FILE: GoogleService-Info.plist gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
run: | --output $HOME/secrets/dist_share_extension.mobileprovision \
mkdir -p $HOME/secrets ./.github/secrets/dist_share_extension.mobileprovision.gpg
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--file src/watchOS/bitwarden/$FILE --output none --output $HOME/secrets/dist_watch_app.mobileprovision \
./.github/secrets/dist_watch_app.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output $HOME/secrets/dist_watch_app_extension.mobileprovision \
./.github/secrets/dist_watch_app_extension.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output ./src/watchOS/bitwarden/GoogleService-Info.plist ./.github/secrets/GoogleService-Info.plist.gpg
- name: Increment version - name: Increment version
run: | run: |
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER)) BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER))
echo "########################################"
echo "##### Setting CFBundleVersion $BUILD_NUMBER" echo "##### Setting CFBundleVersion $BUILD_NUMBER"
echo "### CFBundleVersion $BUILD_NUMBER" >> $GITHUB_STEP_SUMMARY echo "########################################"
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/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
cd src/watchOS/bitwarden cd src/watchOS/bitwarden
agvtool new-version -all $BUILD_NUMBER agvtool new-version -all $BUILD_NUMBER
- name: Update Entitlements - name: Update Entitlements
run: | run: |
echo "########################################"
echo "##### Updating Entitlements" echo "##### Updating Entitlements"
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 echo "########################################"
- name: Get certificates 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
run: |
mkdir -p $HOME/certificates
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/ios-distribution |
jq -r .value | base64 -d > $HOME/certificates/ios-distribution.p12
- name: Set up Keychain - name: Set up Keychain
env: env:
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }} KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
MOBILE_KEY_PASSWORD: ${{ secrets.IOS_KEY_PASSWORD }}
DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
run: | run: |
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
security default-keychain -s build.keychain security default-keychain -s build.keychain
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
security set-keychain-settings -lut 1200 build.keychain security set-keychain-settings -lut 1200 build.keychain
security import ~/secrets/bitwarden-mobile-key.p12 -k build.keychain -P $MOBILE_KEY_PASSWORD \
security import $HOME/certificates/ios-distribution.p12 -k build.keychain -P "" -T /usr/bin/codesign \ -T /usr/bin/codesign -T /usr/bin/security
-T /usr/bin/security security import ~/secrets/iphone-distribution-cert.p12 -k build.keychain -P $DIST_CERT_PASSWORD \
-T /usr/bin/codesign -T /usr/bin/security
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
- name: Set up provisioning profiles - name: Set up provisioning profiles
@@ -564,8 +575,8 @@ jobs:
BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_bitwarden.mobileprovision BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_bitwarden.mobileprovision
EXTENSION_PROFILE_PATH=$HOME/secrets/dist_extension.mobileprovision EXTENSION_PROFILE_PATH=$HOME/secrets/dist_extension.mobileprovision
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app.mobileprovision WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_watch_app.mobileprovision
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app_extension.mobileprovision WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_watch_app_extension.mobileprovision
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
mkdir -p "$PROFILES_DIR_PATH" mkdir -p "$PROFILES_DIR_PATH"
@@ -588,55 +599,85 @@ jobs:
WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}") WATCH_APP_EXTENSION_UUID=$(grep UUID -A1 -a $WATCH_APP_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
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"
- name: Restore packages
run: dotnet restore
- name: Bulid WatchApp - name: Bulid WatchApp
run: | run: |
echo "########################################"
echo "##### Build WatchApp with Release Configuration" echo "##### Build WatchApp with Release Configuration"
echo "########################################"
xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden
echo "########################################"
echo "##### Done"
echo "########################################"
- name: Restore packages
run: nuget restore
- name: Archive Build for App Store - name: Archive Build for App Store
run: | run: |
echo "##### Archive for Release ios-arm64" $configuration = "AppStore";
dotnet publish ${{ env.main_app_project_path }} -c Release -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=ios-arm64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false $platform = "iPhone";
Write-Output "########################################"
Write-Output "##### Archive $configuration Configuration for $platform Platform"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/iOS/iOS.csproj")" "/p:Platform=$platform" `
"/p:Configuration=$configuration" "/p:ArchiveOnBuild=true" "/t:`"Build`""
Write-Output "########################################"
Write-Output "##### Done"
Write-Output "########################################"
shell: pwsh
- name: Archive Build for Mobile Automation - name: Archive Build for Mobile Automation
run: | run: |
echo "##### Archive Debug for iossimulator-x64" $configuration = "Release";
dotnet build ${{ env.main_app_project_path }} -c Debug -f ${{ env.target-net-version }}-ios /p:RuntimeIdentifier=iossimulator-x64 /p:ArchiveOnBuild=true /p:MtouchUseLlvm=false $platform = "iPhoneSimulator";
ls $HOME/Library/Developer/Xcode/Archives
Write-Output "########################################"
Write-Output "##### Archive $configuration Configuration for $platform Platform"
Write-Output "########################################"
msbuild "$($env:GITHUB_WORKSPACE + "/src/iOS/iOS.csproj")" "/p:Platform=$platform" `
"/p:Configuration=$configuration" "/p:ArchiveOnBuild=true" "/t:`"Build`""
Write-Output "########################################"
Write-Output "##### Done"
Write-Output "########################################"
ls ~/Library/Developer/Xcode/Archives
shell: pwsh
- name: Export .ipa for App Store - name: Export .ipa for App Store
env:
EXPORT_OPTIONS_PATH: ./.github/resources/export-options-app-store.plist
EXPORT_PATH: ./bitwarden-export
run: | run: |
EXPORT_OPTIONS_PATH="./.github/resources/export-options-app-store.plist"
ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive" ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive"
EXPORT_PATH="./bitwarden-export"
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \ xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \
-exportOptionsPlist $EXPORT_OPTIONS_PATH -exportOptionsPlist $EXPORT_OPTIONS_PATH
- name: Export .app for Automation CI - name: Export .app for Automation CI
env:
ARCHIVE_PATH: ./${{ env.main_app_folder_path }}/bin/Debug/${{ env.target-net-version }}-ios/iossimulator-x64
EXPORT_PATH: ./bitwarden-export
run: | run: |
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH ARCHIVE_PATH="./src/iOS/bin/iPhoneSimulator/Release/BitwardeniOS.app"
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH EXPORT_PATH="./bitwarden-export"
zip -r -q BitwardeniOS.app.zip $ARCHIVE_PATH
mv BitwardeniOS.app.zip $EXPORT_PATH
- name: Copy all dSYMs files to upload - name: Copy all dSYMs files to upload
env:
EXPORT_PATH: ./bitwarden-export
WATCH_ARCHIVE_DSYMS_PATH: ./src/watchOS/bitwarden.xcarchive/dSYMs/
WATCH_DSYMS_EXPORT_PATH: ./bitwarden-export/Watch_dSYMs
run: | run: |
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs" ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
EXPORT_PATH="./bitwarden-export"
WATCH_ARCHIVE_DSYMS_PATH="./src/watchOS/bitwarden.xcarchive/dSYMs/"
WATCH_DSYMS_EXPORT_PATH="$EXPORT_PATH/Watch_dSYMs"
cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH
mkdir $WATCH_DSYMS_EXPORT_PATH mkdir $WATCH_DSYMS_EXPORT_PATH
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH
- name: Upload App Store .ipa & dSYMs artifacts - name: Upload App Store .ipa & dSYMs artifacts
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: Bitwarden iOS name: Bitwarden iOS
path: | path: |
@@ -645,10 +686,10 @@ jobs:
if-no-files-found: error if-no-files-found: error
- name: Upload .app file for Automation CI - name: Upload .app file for Automation CI
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
with: with:
name: ${{ env.app_ci_output_filename }}.app.zip name: BitwardeniOS.app.zip
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip path: ./bitwarden-export/BitwardeniOS.app.zip
if-no-files-found: error if-no-files-found: error
- name: Install AppCenter CLI - name: Install AppCenter CLI
@@ -679,22 +720,11 @@ jobs:
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0) || (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc' || github.ref == 'refs/heads/hotfix-rc'
run: | run: |
echo "########################################"
echo "##### Uploading Watch dSYMs to Firebase" echo "##### Uploading Watch dSYMs to Firebase"
find "$HOME/Library/Developer/XCode/DerivedData" -name "upload-symbols" -exec chmod +x {} \; -exec {} -gsp "./src/watchOS/bitwarden/GoogleService-Info.plist" -p ios "./bitwarden-export/Watch_dSYMs" \; echo "########################################"
- name: Validate app in App Store find "$HOME/Library/Developer/XCode/DerivedData" -name "upload-symbols" -exec chmod +x {} \; -exec {} -gsp "./src/watchOS/bitwarden/GoogleService-Info.plist" -p ios "./bitwarden-export/Watch_dSYMs" \;
if: |
(github.ref == 'refs/heads/master'
&& needs.setup.outputs.rc_branch_exists == 0
&& needs.setup.outputs.hotfix_branch_exists == 0)
|| (github.ref == 'refs/heads/rc' && needs.setup.outputs.hotfix_branch_exists == 0)
|| github.ref == 'refs/heads/hotfix-rc'
env:
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
run: |
xcrun altool --validate-app --type ios --file "./bitwarden-export/Bitwarden.ipa" \
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
- name: Deploy to App Store - name: Deploy to App Store
if: | if: |
@@ -726,7 +756,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
with: with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
@@ -738,7 +768,7 @@ jobs:
secrets: "crowdin-api-token" secrets: "crowdin-api-token"
- name: Upload Sources - name: Upload Sources
uses: crowdin/github-action@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0 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 }}
@@ -785,7 +815,7 @@ jobs:
fi fi
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 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 }}

View File

@@ -15,10 +15,10 @@ jobs:
_CROWDIN_PROJECT_ID: "269690" _CROWDIN_PROJECT_ID: "269690"
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.6
with: with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
@@ -30,7 +30,7 @@ jobs:
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@c953b17499daa6be3e5afbf7a63616fb02d8b18d # v1.19.0 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 }}

View File

@@ -28,7 +28,7 @@ jobs:
branch-name: ${{ steps.branch.outputs.branch-name }} branch-name: ${{ steps.branch.outputs.branch-name }}
steps: steps:
- name: Branch check - name: Branch check
if: inputs.release_type != 'Dry Run' if: github.event.inputs.release_type != 'Dry Run'
run: | run: |
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
echo "===================================" echo "==================================="
@@ -38,15 +38,15 @@ jobs:
fi fi
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.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@main uses: bitwarden/gh-actions/release-version-check@main
with: with:
release-type: ${{ inputs.release_type }} release-type: ${{ github.event.inputs.release_type }}
project-type: xamarin project-type: xamarin
file: src/App/Platforms/Android/AndroidManifest.xml file: src/Android/Properties/AndroidManifest.xml
- name: Get branch name - name: Get branch name
id: branch id: branch
@@ -55,8 +55,8 @@ jobs:
echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
- name: Create GitHub deployment - name: Create GitHub deployment
if: ${{ inputs.release_type != 'Dry Run' }} if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7 uses: chrnorm/deployment-action@d42cde7132fcec920de534fffc3be83794335c00 # v2.0.5
id: deployment id: deployment
with: with:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
@@ -67,16 +67,16 @@ jobs:
- name: Download all artifacts - name: Download all artifacts
if: ${{ inputs.release_type != 'Dry Run' }} if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
branch: ${{ steps.branch.outputs.branch-name }} branch: ${{ steps.branch.outputs.branch-name }}
- name: Dry Run - Download all artifacts - name: Dry Run - Download all artifacts
if: ${{ inputs.release_type == 'Dry Run' }} if: ${{ github.event.inputs.release_type == 'Dry Run' }}
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
@@ -86,8 +86,8 @@ jobs:
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
- name: Create release - name: Create release
if: ${{ inputs.release_type != 'Dry Run' }} if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.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,
@@ -103,16 +103,16 @@ jobs:
draft: true draft: true
- name: Update deployment status to Success - name: Update deployment status to Success
if: ${{ inputs.release_type != 'Dry Run' && success() }} if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }}
uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
with: with:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
state: 'success' state: 'success'
deployment-id: ${{ steps.deployment.outputs.deployment_id }} deployment-id: ${{ steps.deployment.outputs.deployment_id }}
- name: Update deployment status to Failure - name: Update deployment status to Failure
if: ${{ inputs.release_type != 'Dry Run' && failure() }} if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }}
uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
with: with:
token: '${{ secrets.GITHUB_TOKEN }}' token: '${{ secrets.GITHUB_TOKEN }}'
state: 'failure' state: 'failure'
@@ -126,11 +126,11 @@ jobs:
if: inputs.fdroid_publish if: inputs.fdroid_publish
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Download F-Droid .apk artifact - name: Download F-Droid .apk artifact
if: ${{ inputs.release_type != 'Dry Run' }} if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
@@ -138,8 +138,8 @@ jobs:
name: com.x8bit.bitwarden-fdroid.apk name: com.x8bit.bitwarden-fdroid.apk
- name: Dry Run - Download F-Droid .apk artifact - name: Dry Run - Download F-Droid .apk artifact
if: ${{ inputs.release_type == 'Dry Run' }} if: ${{ github.event.inputs.release_type == 'Dry Run' }}
uses: dawidd6/action-download-artifact@71072fbb1229e1317f1a8de6b04206afb461bd67 # v3.1.2 uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2.27.0
with: with:
workflow: build.yml workflow: build.yml
workflow_conclusion: success workflow_conclusion: success
@@ -147,7 +147,7 @@ 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@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
with: with:
node-version: '16.x' node-version: '16.x'
@@ -176,19 +176,13 @@ jobs:
- name: Install Node dependencies - name: Install Node dependencies
run: npm install run: npm install
- name: Login to Azure - CI Subscription - name: Decrypt secrets
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
- name: Download secrets
env: env:
ACCOUNT_NAME: bitwardenci DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
CONTAINER_NAME: mobile
run: | run: |
mkdir -p $HOME/secrets mkdir -p ~/secrets
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \ gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--name store_fdroid-keystore.jks --file ./store/fdroid/keystore.jks --output none --output ./store/fdroid/keystore.jks ./.github/secrets/store_fdroid-keystore.jks.gpg
- name: Compile for F-Droid Store - name: Compile for F-Droid Store
env: env:
@@ -217,5 +211,5 @@ jobs:
cd $GITHUB_WORKSPACE cd $GITHUB_WORKSPACE
- name: Deploy to gh-pages - name: Deploy to gh-pages
if: ${{ inputs.release_type != 'Dry Run' }} if: ${{ github.event.inputs.release_type != 'Dry Run' }}
run: npm run deploy run: npm run deploy

View File

@@ -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@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.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'

View File

@@ -1,5 +1,5 @@
--- ---
name: Auto Bump Mobile Version name: Version Auto Bump
on: on:
push: push:
@@ -7,12 +7,14 @@ on:
- v** - v**
jobs: jobs:
bump-version: setup:
name: Bump Mobile Version name: "Setup"
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
outputs:
version_number: ${{ steps.version.outputs.new-version }}
steps: steps:
- name: Checkout Branch - name: Checkout Branch
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- name: Calculate bumped version - name: Calculate bumped version
id: version id: version
@@ -27,23 +29,12 @@ jobs:
NEW_PATCH=$((CURR_PATCH+1)) NEW_PATCH=$((CURR_PATCH+1))
NEW_VER=$CURR_MAJOR.$NEW_PATCH NEW_VER=$CURR_MAJOR.$NEW_PATCH
echo "New Version: $NEW_VER" echo "New Version: $NEW_VER"
echo "new_version=$NEW_VER" >> $GITHUB_OUTPUT echo "new-version=$NEW_VER" >> $GITHUB_OUTPUT
- name: Login to Azure - CI Subscription trigger_version_bump:
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 name: Bump version to ${{ needs.setup.outputs.version_number }}
with: needs: setup
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} uses: ./.github/workflows/version-bump.yml
with:
- name: Retrieve bot secrets version_number: ${{ needs.setup.outputs.version_number }}
id: retrieve-bot-secrets secrets: inherit
uses: bitwarden/gh-actions/get-keyvault-secrets@main
with:
keyvault: bitwarden-ci
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
- name: "Bump version to ${{ steps.version.outputs.new_version }}"
env:
GH_TOKEN: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
run: |
echo '{"cut_rc_branch": "false", "version_number": "${{ steps.version.outputs.new_version }}"}' | \
gh workflow run version-bump.yml --json --repo bitwarden/mobile

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
steps: steps:
- name: Login to Azure - CI Subscription - name: Login to Azure - CI Subscription
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 uses: Azure/login@92a5484dfaf04ca78a94597f4f19fea633851fa2 # v1.4.7
with: with:
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
@@ -33,22 +33,13 @@ jobs:
github-pat-bitwarden-devops-bot-repo-scope" github-pat-bitwarden-devops-bot-repo-scope"
- name: Checkout Branch - name: Checkout Branch
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with: with:
ref: main ref: main
repository: bitwarden/mobile
- name: Check if RC branch exists
if: ${{ inputs.cut_rc_branch == true }}
run: |
remote_rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
if [[ "${remote_rc_branch_check}" -gt 0 ]]; then
echo "Remote RC branch exists."
echo "Please delete current RC branch before running again."
exit 1
fi
- name: Import GPG key - name: Import GPG key
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.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 }}
@@ -72,7 +63,7 @@ jobs:
CURRENT_VERSION=$(xmllint --xpath ' CURRENT_VERSION=$(xmllint --xpath '
string(/manifest/@*[local-name()="versionName" string(/manifest/@*[local-name()="versionName"
and namespace-uri()="http://schemas.android.com/apk/res/android"]) and namespace-uri()="http://schemas.android.com/apk/res/android"])
' src/App/Platforms/Android/AndroidManifest.xml) ' src/Android/Properties/AndroidManifest.xml)
# Error if version has not changed. # Error if version has not changed.
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
@@ -93,7 +84,7 @@ jobs:
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }} version: ${{ inputs.version_number }}
file_path: "src/App/Platforms/Android/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@main uses: bitwarden/gh-actions/version-bump@main
@@ -117,7 +108,7 @@ jobs:
uses: bitwarden/gh-actions/version-bump@main uses: bitwarden/gh-actions/version-bump@main
with: with:
version: ${{ inputs.version_number }} version: ${{ inputs.version_number }}
file_path: "src/App/Platforms/iOS/Info.plist" file_path: "src/iOS/Info.plist"
- name: Setup git - name: Setup git
run: | run: |
@@ -192,26 +183,14 @@ jobs:
with: with:
ref: main ref: main
- name: Install xmllint - name: Check if RC branch exists
run: sudo apt install -y libxml2-utils
- name: Verify version has been updated
env:
NEW_VERSION: ${{ inputs.version_number }}
run: | run: |
# Wait for version to change. remote_rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
while : ; do if [[ "${remote_rc_branch_check}" -gt 0 ]]; then
echo "Waiting for version to be updated..." echo "Remote RC branch exists."
git pull --force echo "Please delete current RC branch before running again."
CURRENT_VERSION=$(xmllint --xpath ' exit 1
string(/manifest/@*[local-name()="versionName" fi
and namespace-uri()="http://schemas.android.com/apk/res/android"])
' src/App/Platforms/Android/AndroidManifest.xml)
# If the versions don't match we continue the loop, otherwise we break out of the loop.
[[ "$NEW_VERSION" != "$CURRENT_VERSION" ]] || break
sleep 10
done
- name: Cut RC branch - name: Cut RC branch
run: | run: |

11
.github/workflows/workflow-linter.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
---
name: Workflow Linter
on:
pull_request:
paths:
- .github/workflows/**
jobs:
call-workflow:
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main

1
.gitignore vendored
View File

@@ -31,7 +31,6 @@ 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/

View File

@@ -1,13 +0,0 @@
<Project>
<PropertyGroup>
<MauiVersion>8.0.7</MauiVersion>
<ReleaseCodesignProvision>Automatic:AppStore</ReleaseCodesignProvision>
<ReleaseCodesignKey>iPhone Distribution</ReleaseCodesignKey>
<IncludeBitwardeniOSExtensions>True</IncludeBitwardeniOSExtensions>
<IncludeBitwardenWatchOSApp>True</IncludeBitwardenWatchOSApp>
<Argon2IdLoadMtouchExtraArgs>-gcc_flags "-L$(ProjectDir)../../lib/ios -largon2 -force_load $(ProjectDir)../../lib/ios/libargon2.a"</Argon2IdLoadMtouchExtraArgs>
<!-- Uncomment this when Unit Testing-->
<!-- <CustomConstants>UT</CustomConstants> -->
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,4 @@
[![Github Workflow build on main](https://github.com/bitwarden/mobile/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:main) [![Github Workflow build on master](https://github.com/bitwarden/mobile/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:master)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/bitwarden-mobile/localized.svg)](https://crowdin.com/project/bitwarden-mobile) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/bitwarden-mobile/localized.svg)](https://crowdin.com/project/bitwarden-mobile)
[![Join the chat at https://gitter.im/bitwarden/Lobby](https://badges.gitter.im/bitwarden/Lobby.svg)](https://gitter.im/bitwarden/Lobby) [![Join the chat at https://gitter.im/bitwarden/Lobby](https://badges.gitter.im/bitwarden/Lobby.svg)](https://gitter.im/bitwarden/Lobby)
@@ -6,7 +6,7 @@
<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> <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# using .NET MAUI. The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android-myvault.png" alt="" width="325" height="650" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios-myvault.png" alt="" width="300" height="650" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android-myvault.png" alt="" width="325" height="650" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios-myvault.png" alt="" width="300" height="650" />
@@ -20,6 +20,6 @@ Interested in contributing in a big way? Consider joining our team! We're hiring
# Contribute # Contribute
Code contributions are welcome! Please commit any pull requests against the `main` branch. Learn more about how to contribute by reading the [Contributing Guidelines](https://contributing.bitwarden.com/contributing/). Check out the [Contributing Documentation](https://contributing.bitwarden.com/) for how to get started with your first contribution. Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [Contributing Guidelines](https://contributing.bitwarden.com/contributing/). Check out the [Contributing Documentation](https://contributing.bitwarden.com/) for how to get started with your first contribution.
Security audits and feedback are welcome. Please open an issue or email us privately if the report is sensitive in nature. You can read our security policy in the [`SECURITY.md`](SECURITY.md) file. Security audits and feedback are welcome. Please open an issue or email us privately if the report is sensitive in nature. You can read our security policy in the [`SECURITY.md`](SECURITY.md) file.

View File

@@ -1,233 +1,471 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 16
VisualStudioVersion = 17.8.34112.27 VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{971FDF07-E288-4239-B47A-E9E7E912193B}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{4B8A8C41-9820-4341-974C-41E65B7F4366}"
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", "{83449CC4-1F76-4CFE-92B1-D2E13A62506F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Release|Any CPU = Release|Any CPU
Debug|iPhoneSimulator = Debug|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 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|iPhone = Debug|iPhone
Debug|iPhoneSimulator = Debug|iPhoneSimulator
FDroid|Any CPU = FDroid|Any CPU FDroid|Any CPU = FDroid|Any CPU
FDroid|iPhone = FDroid|iPhone
FDroid|iPhoneSimulator = FDroid|iPhoneSimulator
Release|Any CPU = Release|Any CPU
Release|iPhone = Release|iPhone
Release|iPhoneSimulator = Release|iPhoneSimulator
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.ActiveCfg = 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.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Deploy.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Build.0 = Debug|Any CPU
{971FDF07-E288-4239-B47A-E9E7E912193B}.FDroid|Any CPU.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Deploy.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Deploy.0 = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Build.0 = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Deploy.0 = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Deploy.0 = FDroid|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.ActiveCfg = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Deploy.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.Build.0 = Release|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Deploy.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.FDroid|Any CPU.Build.0 = Debug|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}.Debug|iPhoneSimulator.ActiveCfg = Debug|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.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU {E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU {E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.Build.0 = AppStore|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.Build.0 = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Deploy.0 = Debug|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.ActiveCfg = FDroid|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.Build.0 = FDroid|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.Build.0 = FDroid|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|Any CPU.ActiveCfg = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.ActiveCfg = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = Release|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.Build.0 = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.Build.0 = AppStore|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = AppStore|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Deploy.0 = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|iPhone
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|iPhone
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.Build.0 = Debug|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.ActiveCfg = Release|Any CPU {324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.ActiveCfg = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.ActiveCfg = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.Build.0 = Release|Any CPU
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.FDroid|Any CPU.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|Any CPU.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|Any CPU.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhone.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhone.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhone.ActiveCfg = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhone.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhone.ActiveCfg = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhone.Build.0 = Release|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.FDroid|Any CPU.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|Any CPU.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|Any CPU.ActiveCfg = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|Any CPU.Build.0 = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhone.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhone.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhone.ActiveCfg = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhone.Build.0 = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhone.ActiveCfg = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhone.Build.0 = Release|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU {8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.FDroid|Any CPU.Build.0 = Debug|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(ExtensibilityGlobals) = postSolution
SolutionGuid = {3B3A9B6C-D325-4BB3-97D3-8070630C5D3B}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = PrefixedHierarchical
EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{971FDF07-E288-4239-B47A-E9E7E912193B} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC} {304400AF-F0ED-40FA-B102-EA3C3EC43E4F} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC} {EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{83449CC4-1F76-4CFE-92B1-D2E13A62506F} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC} {4B8A8C41-9820-4341-974C-41E65B7F4366} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{E71F3053-056C-4381-9638-048ED73BDFF6} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC} {9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3} = {8904C536-C67D-420F-9971-51B26574C3AA}
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC} {2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC} {256F9E44-0AF5-4D97-A2F9-DA26080C0A5D} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6} = {BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0} {E71F3053-056C-4381-9638-048ED73BDFF6} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44} = {BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0} {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
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@@ -67,7 +67,7 @@ Task("UpdateAndroidManifest")
.Does(()=> .Does(()=>
{ {
var buildVariant = GetVariant(); var buildVariant = GetVariant();
var manifestPath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "AndroidManifest.xml"); var manifestPath = Path.Combine(_slnPath, "src", "Android", "Properties", "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", "App", "Platforms", "Android", "Services", "BiometricService.cs"); var filePath = Path.Combine(_slnPath, "src", "Android", "Services", "BiometricService.cs");
ReplaceInFile(filePath, keyName, fixedPackageName); ReplaceInFile(filePath, keyName, fixedPackageName);
var packageFileList = new string[] { var packageFileList = new string[] {
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainActivity.cs"), Path.Combine(_slnPath, "src", "Android", "MainActivity.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainApplication.cs"), Path.Combine(_slnPath, "src", "Android", "MainApplication.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Constants.cs"), Path.Combine(_slnPath, "src", "Android", "Constants.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Accessibility", "AccessibilityService.cs"), Path.Combine(_slnPath, "src", "Android", "Accessibility", "AccessibilityService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillHelpers.cs"), Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillHelpers.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"), Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"), Path.Combine(_slnPath, "src", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "EventUploadReceiver.cs"), Path.Combine(_slnPath, "src", "Android", "Receivers", "EventUploadReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "PackageReplacedReceiver.cs"), Path.Combine(_slnPath, "src", "Android", "Receivers", "PackageReplacedReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "RestrictionsChangedReceiver.cs"), Path.Combine(_slnPath, "src", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "DeviceActionService.cs"), Path.Combine(_slnPath, "src", "Android", "Services", "DeviceActionService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "FileService.cs"), Path.Combine(_slnPath, "src", "Android", "Services", "FileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "AutofillTileService.cs"), Path.Combine(_slnPath, "src", "Android", "Tiles", "AutofillTileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "GeneratorTileService.cs"), Path.Combine(_slnPath, "src", "Android", "Tiles", "GeneratorTileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "MyVaultTileService.cs"), Path.Combine(_slnPath, "src", "Android", "Tiles", "MyVaultTileService.cs"),
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "google-services.json"), Path.Combine(_slnPath, "src", "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", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"), Path.Combine(_slnPath, "src", "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", "App", "Platforms", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset")); UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "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", "App", "Platforms", "iOS", "Info.plist"); var infoPath = Path.Combine(_slnPath, "src", "iOS", "Info.plist");
var entitlementsPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Entitlements.plist"); var entitlementsPath = Path.Combine(_slnPath, "src", "iOS", "Entitlements.plist");
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp); UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant); UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
}); });

View File

@@ -2,9 +2,9 @@ project_id_env: _CROWDIN_PROJECT_ID
api_token_env: CROWDIN_API_TOKEN api_token_env: CROWDIN_API_TOKEN
preserve_hierarchy: true preserve_hierarchy: true
files: files:
- source: /src/Core/Resources/Localization/AppResources.resx - source: /src/App/Resources/AppResources.resx
dest: /src/Core/Resources/Localization/%original_file_name% dest: /src/App/Resources/%original_file_name%
translation: /src/Core/Resources/Localization/AppResources.%two_letters_code%.resx translation: /src/App/Resources/AppResources.%two_letters_code%.resx
update_option: update_as_unapproved update_option: update_as_unapproved
languages_mapping: languages_mapping:
two_letters_code: two_letters_code:

7
global.json Normal file
View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "7.0.400",
"rollForward": "latestPatch",
"allowPrerelease": false
}
}

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="MAUI Nightly builds" value="https://pkgs.dev.azure.com/xamarin/public/_packaging/maui-nightly/nuget/v3/index.json" />
</packageSources>
</configuration>

12
package-lock.json generated
View File

@@ -33,9 +33,9 @@
} }
}, },
"node_modules/async": { "node_modules/async": {
"version": "2.6.3", "version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"lodash": "^4.17.14" "lodash": "^4.17.14"
@@ -480,9 +480,9 @@
"dev": true "dev": true
}, },
"async": { "async": {
"version": "2.6.3", "version": "2.6.4",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
"dev": true, "dev": true,
"requires": { "requires": {
"lodash": "^4.17.14" "lodash": "^4.17.14"

View File

@@ -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.App.Droid.Utilities; using Bit.Droid.Utilities;
namespace Bit.Droid.Accessibility namespace Bit.Droid.Accessibility
{ {

View File

@@ -10,13 +10,8 @@ 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.Core.Resources.Localization; using Bit.App.Resources;
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
{ {
@@ -710,7 +705,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(Bit.Core.Resource.Layout.autofill_listitem, null); var view = (LinearLayout)inflater.Inflate(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);

View File

@@ -9,10 +9,9 @@ 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.Core.Resources.Localization; using Bit.App.Resources;
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
{ {

327
src/Android/Android.csproj Normal file
View File

@@ -0,0 +1,327 @@
<?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.6.1.3" />
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.21" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.10.1.2" />
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.4.0.2" />
<PackageReference Include="Xamarin.Essentials">
<Version>1.8.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Firebase.Messaging">
<Version>123.1.2.2</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.9.0.2" />
<PackageReference Include="Xamarin.Google.Dagger" Version="2.46.1.2" />
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
<Version>118.0.1.5</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" />
<Compile Include="Renderers\CustomLabelRenderer.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>
<AndroidResource Include="Resources\layout\validatable_input_dialog_layout.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\empty_uris_placeholder.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\empty_uris_placeholder_dark.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\empty_login_requests.xml">
<SubType></SubType>
<Generator></Generator>
</AndroidResource>
<AndroidResource Include="Resources\drawable\empty_login_requests_dark.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>

View File

@@ -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.App.Droid.Utilities; using Bit.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 : MauiAppCompatActivity public class AutofillExternalSelectionActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{ {
protected override void OnCreate(Bundle bundle) protected override void OnCreate(Bundle bundle)
{ {

View File

@@ -12,17 +12,15 @@ 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.Core.Resources.Localization; using Bit.App.Resources;
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.App.Droid.Utilities; using Bit.Droid.Utilities;
using Bit.Core.Services; using Bit.Core.Services;
using Resource = Bit.Core.Resource;
using BlendMode = Android.Graphics.BlendMode;
namespace Bit.Droid.Autofill namespace Bit.Droid.Autofill
{ {

View File

@@ -6,7 +6,6 @@ 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
{ {

View File

@@ -4,7 +4,6 @@ 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
{ {

View File

@@ -4,7 +4,6 @@ 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
{ {

View File

@@ -0,0 +1,30 @@
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 ()
{
}
}
}

View File

@@ -0,0 +1,23 @@
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()
{
}
}
}

View File

@@ -1,20 +1,12 @@
using System; using Android.Widget;
using Microsoft.Maui.Controls; using Bit.Droid.Effects;
using Microsoft.Maui; using Xamarin.Forms;
using Microsoft.Maui.Controls.Platform; using Xamarin.Forms.Platform.Android;
#if ANDROID [assembly: ExportEffect(typeof(NoEmojiKeyboardEffect), nameof(NoEmojiKeyboardEffect))]
using Android.Widget; namespace Bit.Droid.Effects
#endif
namespace Bit.App.Effects
{ {
public class NoEmojiKeyboardEffect : RoutingEffect public class NoEmojiKeyboardEffect : PlatformEffect
{
}
#if ANDROID
public class NoEmojiKeyboardPlatformEffect : PlatformEffect
{ {
protected override void OnAttached() protected override void OnAttached()
{ {
@@ -28,5 +20,5 @@ namespace Bit.App.Effects
{ {
} }
} }
#endif
} }

View File

@@ -0,0 +1,23 @@
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()
{
}
}
}

View File

@@ -0,0 +1,30 @@
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()
{
}
}
}

View File

@@ -12,7 +12,7 @@ using Android.Runtime;
using Android.Views; using Android.Views;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Models; using Bit.App.Models;
using Bit.Core.Resources.Localization; using Bit.App.Resources;
using Bit.App.Utilities; using Bit.App.Utilities;
using Bit.Core; using Bit.Core;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
@@ -20,9 +20,11 @@ using Bit.Core.Enums;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Droid.Autofill; using Bit.Droid.Autofill;
using Bit.Droid.Receivers; using Bit.Droid.Receivers;
using Bit.App.Droid.Utilities; using Bit.Droid.Utilities;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Xamarin.Essentials;
using ZXing.Net.Mobile.Android;
using FileProvider = AndroidX.Core.Content.FileProvider; using FileProvider = AndroidX.Core.Content.FileProvider;
namespace Bit.Droid namespace Bit.Droid
@@ -32,7 +34,7 @@ namespace Bit.Droid
// LaunchMode defined in values/manifest.xml for Android 10- and values-v30/manifest.xml for Android 11+ // LaunchMode defined in values/manifest.xml for Android 10- and values-v30/manifest.xml for Android 11+
// See https://github.com/bitwarden/mobile/pull/1673 for details // See https://github.com/bitwarden/mobile/pull/1673 for details
[Register("com.x8bit.bitwarden.MainActivity")] [Register("com.x8bit.bitwarden.MainActivity")]
public class MainActivity : MauiAppCompatActivity public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{ {
private IDeviceActionService _deviceActionService; private IDeviceActionService _deviceActionService;
private IFileService _fileService; private IFileService _fileService;
@@ -68,17 +70,12 @@ namespace Bit.Droid
_pushNotificationListenerService = ServiceContainer.Resolve<IPushNotificationListenerService>(); _pushNotificationListenerService = ServiceContainer.Resolve<IPushNotificationListenerService>();
_logger = ServiceContainer.Resolve<ILogger>("logger"); _logger = ServiceContainer.Resolve<ILogger>("logger");
//TabLayoutResource = Resource.Layout.Tabbar; TabLayoutResource = Resource.Layout.Tabbar;
//ToolbarResource = Resource.Layout.Toolbar; ToolbarResource = Resource.Layout.Toolbar;
// this needs to be called here before base.OnCreate(...) // this needs to be called here before base.OnCreate(...)
Intent?.Validate(); Intent?.Validate();
//We need to get and set the Options before calling OnCreate as that will "trigger" CreateWindow on App.xaml.cs
_appOptions = GetOptions();
//This does not replace existing Options in App.xaml.cs if it exists already. It only updates properties in Options related with Autofill/CreateSend/etc..
((Bit.App.App)Microsoft.Maui.Controls.Application.Current).SetAndroidOptions(_appOptions);
base.OnCreate(savedInstanceState); base.OnCreate(savedInstanceState);
_deviceActionService.SetScreenCaptureAllowedAsync().FireAndForget(_ => _deviceActionService.SetScreenCaptureAllowedAsync().FireAndForget(_ =>
@@ -94,7 +91,11 @@ namespace Bit.Droid
toplayout.FilterTouchesWhenObscured = true; toplayout.FilterTouchesWhenObscured = true;
} }
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
Xamarin.Forms.Forms.Init(this, savedInstanceState);
_appOptions = GetOptions();
CreateNotificationChannel(); CreateNotificationChannel();
LoadApplication(new App.App(_appOptions));
DisableAndroidFontScale(); DisableAndroidFontScale();
_broadcasterService.Subscribe(_activityKey, (message) => _broadcasterService.Subscribe(_activityKey, (message) =>
@@ -109,7 +110,7 @@ namespace Bit.Droid
} }
else if (message.Command == "finishMainActivity") else if (message.Command == "finishMainActivity")
{ {
MainThread.BeginInvokeOnMainThread(() => Finish()); Xamarin.Forms.Device.BeginInvokeOnMainThread(() => Finish());
} }
else if (message.Command == "listenYubiKeyOTP") else if (message.Command == "listenYubiKeyOTP")
{ {
@@ -117,7 +118,7 @@ namespace Bit.Droid
} }
else if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY) else if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY)
{ {
MainThread.BeginInvokeOnMainThread(() => AppearanceAdjustments()); Xamarin.Forms.Device.BeginInvokeOnMainThread(() => AppearanceAdjustments());
} }
else if (message.Command == "exit") else if (message.Command == "exit")
{ {
@@ -135,7 +136,7 @@ namespace Bit.Droid
protected override void OnResume() protected override void OnResume()
{ {
base.OnResume(); base.OnResume();
//Xamarin.Essentials.Platform.OnResume(); Xamarin.Essentials.Platform.OnResume();
AppearanceAdjustments(); AppearanceAdjustments();
ThemeManager.UpdateThemeOnPagesAsync(); ThemeManager.UpdateThemeOnPagesAsync();
@@ -223,9 +224,8 @@ namespace Bit.Droid
} }
else else
{ {
Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults); Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
//Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults); PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
//PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
} }
base.OnRequestPermissionsResult(requestCode, permissions, grantResults); base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
} }

View File

@@ -12,6 +12,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Services; using Bit.Core.Services;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.Droid.Services; using Bit.Droid.Services;
using Plugin.CurrentActivity;
using Plugin.Fingerprint; using Plugin.Fingerprint;
using Xamarin.Android.Net; using Xamarin.Android.Net;
using System.Net.Http; using System.Net.Http;
@@ -24,7 +25,6 @@ using Bit.Core.Enums;
#if !FDROID #if !FDROID
using Android.Gms.Security; using Android.Gms.Security;
#endif #endif
using DeviceType = Bit.Core.Enums.DeviceType;
namespace Bit.Droid namespace Bit.Droid
{ {
@@ -35,9 +35,9 @@ namespace Bit.Droid
#endif #endif
[Register("com.x8bit.bitwarden.MainApplication")] [Register("com.x8bit.bitwarden.MainApplication")]
#if FDROID #if FDROID
public class MainApplication : MauiApplication public class MainApplication : Application
#else #else
public class MainApplication : MauiApplication, ProviderInstaller.IProviderInstallListener public class MainApplication : Application, ProviderInstaller.IProviderInstallListener
#endif #endif
{ {
public MainApplication(IntPtr handle, JniHandleOwnership transer) public MainApplication(IntPtr handle, JniHandleOwnership transer)
@@ -94,12 +94,11 @@ namespace Bit.Droid
#endif #endif
} }
protected override MauiApp CreateMauiApp() => App.MauiProgram.CreateMauiApp();
public override void OnCreate() public override void OnCreate()
{ {
base.OnCreate(); base.OnCreate();
Bootstrap(); Bootstrap();
CrossCurrentActivity.Current.Init(this);
} }
public void OnProviderInstallFailed(int errorCode, Intent recoveryIntent) public void OnProviderInstallFailed(int errorCode, Intent recoveryIntent)
@@ -123,22 +122,22 @@ namespace Bit.Droid
ServiceContainer.Register("logger", logger); ServiceContainer.Register("logger", logger);
// Note: This might cause a race condition. Investigate more. // Note: This might cause a race condition. Investigate more.
//Task.Run(() => Task.Run(() =>
//{ {
// FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true); FFImageLoading.Forms.Platform.CachedImageRenderer.Init(true);
// FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration
// { {
// FadeAnimationEnabled = false, FadeAnimationEnabled = false,
// FadeAnimationForCachedImages = false, FadeAnimationForCachedImages = false,
// HttpClient = new HttpClient(new AndroidClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }) HttpClient = new HttpClient(new AndroidClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate })
// }); });
// ZXing.Net.Mobile.Forms.Android.Platform.Init(); ZXing.Net.Mobile.Forms.Android.Platform.Init();
//}); });
CrossFingerprint.SetCurrentActivityResolver(() => Microsoft.Maui.ApplicationModel.Platform.CurrentActivity); CrossFingerprint.SetCurrentActivityResolver(() => CrossCurrentActivity.Current.Activity);
var preferencesStorage = new PreferencesStorageService(null); var preferencesStorage = new PreferencesStorageService(null);
var localAppDataFolderPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData); var documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
var liteDbStorage = new LiteDbStorageService(Path.Combine(localAppDataFolderPath, "bitwarden.db")); var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db"));
var localizeService = new LocalizeService(); var localizeService = new LocalizeService();
var broadcasterService = new BroadcasterService(logger); var broadcasterService = new BroadcasterService(logger);
var messagingService = new MobileBroadcasterMessagingService(broadcasterService); var messagingService = new MobileBroadcasterMessagingService(broadcasterService);
@@ -149,7 +148,7 @@ namespace Bit.Droid
var storageMediatorService = new StorageMediatorService(mobileStorageService, secureStorageService, preferencesStorage); var storageMediatorService = new StorageMediatorService(mobileStorageService, secureStorageService, preferencesStorage);
var stateService = new StateService(mobileStorageService, secureStorageService, storageMediatorService, messagingService); var stateService = new StateService(mobileStorageService, secureStorageService, storageMediatorService, messagingService);
var stateMigrationService = var stateMigrationService =
new StateMigrationService(Bit.Core.Enums.DeviceType.Android, liteDbStorage, preferencesStorage, secureStorageService); new StateMigrationService(DeviceType.Android, liteDbStorage, preferencesStorage, secureStorageService);
var clipboardService = new ClipboardService(stateService); var clipboardService = new ClipboardService(stateService);
var deviceActionService = new DeviceActionService(stateService, messagingService); var deviceActionService = new DeviceActionService(stateService, messagingService);
var fileService = new FileService(stateService, broadcasterService); var fileService = new FileService(stateService, broadcasterService);
@@ -158,7 +157,7 @@ namespace Bit.Droid
var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService, var autofillHandler = new AutofillHandler(stateService, messagingService, clipboardService,
platformUtilsService, new LazyResolve<IEventService>()); platformUtilsService, new LazyResolve<IEventService>());
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService); var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(stateService, cryptoFunctionService, logger); var cryptoService = new CryptoService(stateService, cryptoFunctionService);
var biometricService = new BiometricService(stateService, cryptoService); var biometricService = new BiometricService(stateService, cryptoService);
var userPinService = new UserPinService(stateService, cryptoService); var userPinService = new UserPinService(stateService, cryptoService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService); var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService, stateService);

View File

@@ -1,6 +1,6 @@
<?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="2024.2.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="2024.1.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" /> <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" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

View File

@@ -0,0 +1,28 @@
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")]

View File

@@ -8,6 +8,7 @@ using Bit.Core.Utilities;
using Firebase.Messaging; using Firebase.Messaging;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Xamarin.Forms;
namespace Bit.Droid.Push namespace Bit.Droid.Push
{ {

View File

@@ -4,7 +4,7 @@ using Android.Content;
using Bit.App.Utilities; using Bit.App.Utilities;
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Bit.App.Droid.Utilities; using Bit.Droid.Utilities;
namespace Bit.Droid.Receivers namespace Bit.Droid.Receivers
{ {

View File

@@ -0,0 +1,69 @@
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);
}
}
}
}

View File

@@ -0,0 +1,107 @@
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);
}
}
}
}

View File

@@ -0,0 +1,43 @@
using System.ComponentModel;
using Android.Content;
using Android.OS;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CustomLabel), typeof(CustomLabelRenderer))]
namespace Bit.Droid.Renderers
{
public class CustomLabelRenderer : LabelRenderer
{
public CustomLabelRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null && e.NewElement is CustomLabel label)
{
if (label.FontWeight.HasValue && Build.VERSION.SdkInt >= BuildVersionCodes.P)
{
Control.Typeface = Android.Graphics.Typeface.Create(null, label.FontWeight.Value, false);
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var label = sender as CustomLabel;
switch (e.PropertyName)
{
case nameof(CustomLabel.AutomationId):
Control.ContentDescription = label.AutomationId;
break;
}
base.OnElementPropertyChanged(sender, e);
}
}
}

View File

@@ -0,0 +1,31 @@
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;
}
}
}
}

View File

@@ -0,0 +1,57 @@
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);
}
}
}
}

View File

@@ -0,0 +1,33 @@
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);
}
}
}
}

View File

@@ -0,0 +1,67 @@
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);
}
}
}
}

View File

@@ -0,0 +1,66 @@
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());
}
}
}
}

View File

@@ -0,0 +1,50 @@
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);
}
}
}

View File

@@ -0,0 +1,23 @@
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);
}
}
}
}

View File

@@ -0,0 +1,56 @@
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);
}
}
}
}
}

View File

@@ -0,0 +1,23 @@
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);
}
}
}
}

View File

@@ -0,0 +1,72 @@
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());
}
}
}
}

View File

@@ -0,0 +1,50 @@
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);
}
}
}

View File

@@ -0,0 +1,98 @@
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);
}
}
}
}

View File

@@ -0,0 +1,25 @@
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);
}
}
}
}

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 187 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 381 KiB

Some files were not shown because too many files have changed in this diff Show More