mirror of
https://github.com/bitwarden/mobile
synced 2026-01-08 03:23:23 +00:00
Compare commits
106 Commits
beta-nativ
...
v2024.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62262269bc | ||
|
|
98621341a2 | ||
|
|
2023fe6644 | ||
|
|
567a23e29f | ||
|
|
8b65d99442 | ||
|
|
f80ec1b221 | ||
|
|
ba1183234b | ||
|
|
5946af9eec | ||
|
|
b091051633 | ||
|
|
06488539b0 | ||
|
|
8f77822b1b | ||
|
|
3c1105b35d | ||
|
|
c847449db8 | ||
|
|
c2771eb3c7 | ||
|
|
6e41731dcb | ||
|
|
7c90b35592 | ||
|
|
93f9dc4498 | ||
|
|
e033832261 | ||
|
|
fa5d92fbf7 | ||
|
|
e672cb132f | ||
|
|
e7a7eed7e8 | ||
|
|
43a4915323 | ||
|
|
b1ae3cc325 | ||
|
|
b9dada07ea | ||
|
|
58442389df | ||
|
|
a3378d33ae | ||
|
|
2e1982b08e | ||
|
|
e9e9b6f7bc | ||
|
|
9be8fec219 | ||
|
|
9db32ca019 | ||
|
|
f04ff7777a | ||
|
|
64775694e0 | ||
|
|
3c0007a21a | ||
|
|
35ff235010 | ||
|
|
01bd5a7b8d | ||
|
|
3fce8c76bc | ||
|
|
3b64d7b979 | ||
|
|
f343a2cdbb | ||
|
|
9a9fb85ad8 | ||
|
|
e7f9d64edb | ||
|
|
459d20c019 | ||
|
|
a8529fa4b7 | ||
|
|
d1e82c9f1d | ||
|
|
9bc2901255 | ||
|
|
e3441845cd | ||
|
|
3f463647a0 | ||
|
|
4f169a6fe3 | ||
|
|
82c2e91446 | ||
|
|
7482808857 | ||
|
|
fd233fa27f | ||
|
|
19f238d9bb | ||
|
|
6f6487ccc9 | ||
|
|
dd3dc82595 | ||
|
|
40c80f082d | ||
|
|
bca5b95446 | ||
|
|
602627b5fa | ||
|
|
6f32afb919 | ||
|
|
2ca47a4da4 | ||
|
|
4ff56ba11e | ||
|
|
22d0cc681c | ||
|
|
4e0a18cce5 | ||
|
|
c9fdfa7a15 | ||
|
|
850a7e754a | ||
|
|
67c5f79625 | ||
|
|
04e7cfe06d | ||
|
|
d6c2ebe4c2 | ||
|
|
2a28294f91 | ||
|
|
8584bbaecc | ||
|
|
2f3cded9c5 | ||
|
|
eff0ea7ce7 | ||
|
|
6c3a53dd76 | ||
|
|
cf8d801c55 | ||
|
|
eaa6844742 | ||
|
|
29e2f728e0 | ||
|
|
fe160a570f | ||
|
|
a508bea4b0 | ||
|
|
a73923c4f7 | ||
|
|
11465e8975 | ||
|
|
4c88524f0e | ||
|
|
f1c20e03bc | ||
|
|
920a2273c5 | ||
|
|
96a9978ef8 | ||
|
|
1ae388cb03 | ||
|
|
c6aaf5002f | ||
|
|
75be6504e1 | ||
|
|
cae1825e3f | ||
|
|
c23100d281 | ||
|
|
c9c0d0b4d6 | ||
|
|
fec0743e4d | ||
|
|
118dcf164c | ||
|
|
bd03b6b5aa | ||
|
|
333917c00d | ||
|
|
450101d9e4 | ||
|
|
4e50f1697d | ||
|
|
3c96ae2220 | ||
|
|
fdbd16a6fd | ||
|
|
39a34bd8c4 | ||
|
|
f30158adf5 | ||
|
|
c6a086fe62 | ||
|
|
b217451ea9 | ||
|
|
8cb7d5e1a3 | ||
|
|
82b837ef33 | ||
|
|
ebb2a288a1 | ||
|
|
de7ae27a77 | ||
|
|
d3dd2e9342 | ||
|
|
a5878d3341 |
14
.github/CODEOWNERS
vendored
14
.github/CODEOWNERS
vendored
@@ -10,11 +10,17 @@
|
|||||||
# 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 ##
|
||||||
appIcons @bitwarden/team-platform-dev
|
appIcons @bitwarden/team-platform-dev
|
||||||
build.cake @bitwarden/team-platform-dev
|
|
||||||
|
|
||||||
## Vault team files ##
|
## Vault team files ##
|
||||||
src/watchOS @bitwarden/team-vault-dev
|
src/watchOS @bitwarden/team-vault-dev
|
||||||
@@ -23,14 +29,14 @@ src/watchOS @bitwarden/team-vault-dev
|
|||||||
src/Core/Services/EmailForwarders @bitwarden/team-tools-dev
|
src/Core/Services/EmailForwarders @bitwarden/team-tools-dev
|
||||||
|
|
||||||
## Crowdin Sync files ##
|
## Crowdin Sync files ##
|
||||||
src/App/Resources @bitwarden/team-tools-dev
|
src/Core/Resources/Localization @bitwarden/team-tools-dev
|
||||||
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/team-tools-dev
|
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization @bitwarden/team-tools-dev
|
||||||
store/apple @bitwarden/team-tools-dev
|
store/apple @bitwarden/team-tools-dev
|
||||||
store/google @bitwarden/team-tools-dev
|
store/google @bitwarden/team-tools-dev
|
||||||
|
|
||||||
## Locales ##
|
## Locales ##
|
||||||
src/App/Resources/AppResources.Designer.cs
|
src/Core/Resources/Localization/AppResources.Designer.cs
|
||||||
src/App/Resources/AppResources.resx
|
src/Core/Resources/Localization/AppResources.resx
|
||||||
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj
|
src/watchOS/bitwarden/bitwarden\ WatchKit\ Extension/Localization/en.lproj
|
||||||
store/apple/en
|
store/apple/en
|
||||||
store/google/en
|
store/google/en
|
||||||
|
|||||||
BIN
.github/secrets/GoogleService-Info.plist.gpg
vendored
BIN
.github/secrets/GoogleService-Info.plist.gpg
vendored
Binary file not shown.
BIN
.github/secrets/app_fdroid-keystore.jks.gpg
vendored
BIN
.github/secrets/app_fdroid-keystore.jks.gpg
vendored
Binary file not shown.
BIN
.github/secrets/app_play-keystore.jks.gpg
vendored
BIN
.github/secrets/app_play-keystore.jks.gpg
vendored
Binary file not shown.
BIN
.github/secrets/app_upload-keystore.jks.gpg
vendored
BIN
.github/secrets/app_upload-keystore.jks.gpg
vendored
Binary file not shown.
BIN
.github/secrets/bitwarden-mobile-key.p12.gpg
vendored
BIN
.github/secrets/bitwarden-mobile-key.p12.gpg
vendored
Binary file not shown.
BIN
.github/secrets/dist_autofill.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_autofill.mobileprovision.gpg
vendored
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.
BIN
.github/secrets/dist_bitwarden.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_bitwarden.mobileprovision.gpg
vendored
Binary file not shown.
BIN
.github/secrets/dist_extension.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_extension.mobileprovision.gpg
vendored
Binary file not shown.
Binary file not shown.
BIN
.github/secrets/dist_watch_app.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_watch_app.mobileprovision.gpg
vendored
Binary file not shown.
Binary file not shown.
3
.github/secrets/google-services.json.gpg
vendored
3
.github/secrets/google-services.json.gpg
vendored
@@ -1,3 +0,0 @@
|
|||||||
<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>
|
|
||||||
BIN
.github/secrets/iphone-distribution-cert.p12.gpg
vendored
BIN
.github/secrets/iphone-distribution-cert.p12.gpg
vendored
Binary file not shown.
BIN
.github/secrets/play_creds.json.gpg
vendored
BIN
.github/secrets/play_creds.json.gpg
vendored
Binary file not shown.
BIN
.github/secrets/store_fdroid-keystore.jks.gpg
vendored
BIN
.github/secrets/store_fdroid-keystore.jks.gpg
vendored
Binary file not shown.
350
.github/workflows/build-beta.yml
vendored
Normal file
350
.github/workflows/build-beta.yml
vendored
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
---
|
||||||
|
name: Build Beta
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
ref:
|
||||||
|
description: 'Branch or tag to build'
|
||||||
|
required: true
|
||||||
|
default: 'main'
|
||||||
|
type: string
|
||||||
|
|
||||||
|
env:
|
||||||
|
main_app_folder_path: src/App
|
||||||
|
main_app_project_path: src/App/App.csproj
|
||||||
|
target-net-version: net8.0
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
setup:
|
||||||
|
name: Setup
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
outputs:
|
||||||
|
rc_branch_exists: ${{ steps.branch-check.outputs.rc_branch_exists }}
|
||||||
|
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
|
- name: Check if special branches exist
|
||||||
|
id: branch-check
|
||||||
|
run: |
|
||||||
|
if [[ $(git ls-remote --heads origin rc) ]]; then
|
||||||
|
echo "rc_branch_exists=1" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "rc_branch_exists=0" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $(git ls-remote --heads origin hotfix-rc) ]]; then
|
||||||
|
echo "hotfix_branch_exists=1" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
ios:
|
||||||
|
name: Apple iOS
|
||||||
|
runs-on: macos-14
|
||||||
|
needs: setup
|
||||||
|
env:
|
||||||
|
ios_folder_path: src/App/Platforms/iOS
|
||||||
|
app_output_name: App
|
||||||
|
app_ci_output_filename: App_x64_Debug
|
||||||
|
steps:
|
||||||
|
- name: Set XCode version
|
||||||
|
uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
|
||||||
|
with:
|
||||||
|
xcode-version: 15.1
|
||||||
|
|
||||||
|
- name: Setup NuGet
|
||||||
|
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||||
|
with:
|
||||||
|
nuget-version: 6.4.0
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.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
|
||||||
|
run: |
|
||||||
|
nuget help | grep Version
|
||||||
|
dotnet --info
|
||||||
|
echo "GitHub ref: $GITHUB_REF"
|
||||||
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ inputs.ref }}
|
||||||
|
submodules: 'true'
|
||||||
|
|
||||||
|
- name: Login to Azure - CI Subscription
|
||||||
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
|
- name: Retrieve secrets
|
||||||
|
id: retrieve-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
with:
|
||||||
|
keyvault: "bitwarden-ci"
|
||||||
|
secrets: "appcenter-ios-token"
|
||||||
|
|
||||||
|
- name: Download Provisioning Profiles secrets
|
||||||
|
env:
|
||||||
|
ACCOUNT_NAME: bitwardenci
|
||||||
|
CONTAINER_NAME: profiles
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/secrets
|
||||||
|
profiles=(
|
||||||
|
"dist_beta_autofill.mobileprovision"
|
||||||
|
"dist_beta_bitwarden.mobileprovision"
|
||||||
|
"dist_beta_extension.mobileprovision"
|
||||||
|
"dist_beta_share_extension.mobileprovision"
|
||||||
|
"dist_beta_bitwarden_watch_app.mobileprovision"
|
||||||
|
"dist_beta_bitwarden_watch_app_extension.mobileprovision"
|
||||||
|
)
|
||||||
|
|
||||||
|
for FILE in "${profiles[@]}"
|
||||||
|
do
|
||||||
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||||
|
--file $HOME/secrets/$FILE --output none
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Download Google Services secret
|
||||||
|
env:
|
||||||
|
ACCOUNT_NAME: bitwardenci
|
||||||
|
CONTAINER_NAME: mobile
|
||||||
|
FILE: GoogleService-Info.plist
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/secrets
|
||||||
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||||
|
--file $HOME/secrets/$FILE --output none
|
||||||
|
|
||||||
|
- name: Increment version
|
||||||
|
run: |
|
||||||
|
BUILD_NUMBER=$((100 + $GITHUB_RUN_NUMBER))
|
||||||
|
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
|
||||||
|
|
||||||
|
echo "### CFBundleVersion $BUILD_NUMBER" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./${{ env.ios_folder_path }}/Info.plist
|
||||||
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.Extension/Info.plist
|
||||||
|
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS.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
|
||||||
|
cd src/watchOS/bitwarden
|
||||||
|
agvtool new-version -all $BUILD_NUMBER
|
||||||
|
|
||||||
|
- name: Update Entitlements
|
||||||
|
run: |
|
||||||
|
echo "##### Updating Entitlements"
|
||||||
|
perl -0777 -pi.bak -e 's/<key>aps-environment<\/key>\s*<string>development<\/string>/<key>aps-environment<\/key>\n\t<string>beta<\/string>/' ./${{ env.ios_folder_path }}/Entitlements.plist
|
||||||
|
|
||||||
|
- name: Get certificates
|
||||||
|
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
|
||||||
|
env:
|
||||||
|
KEYCHAIN_PASSWORD: ${{ secrets.IOS_KEYCHAIN_PASSWORD }}
|
||||||
|
MOBILE_KEY_PASSWORD: ${{ secrets.IOS_KEY_PASSWORD }}
|
||||||
|
DIST_CERT_PASSWORD: ${{ secrets.IOS_DIST_CERT_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||||
|
security default-keychain -s build.keychain
|
||||||
|
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||||
|
security set-keychain-settings -lut 1200 build.keychain
|
||||||
|
|
||||||
|
security import $HOME/certificates/ios-distribution.p12 -k build.keychain -P "" -T /usr/bin/codesign \
|
||||||
|
-T /usr/bin/security
|
||||||
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||||
|
|
||||||
|
- name: Set up provisioning profiles
|
||||||
|
run: |
|
||||||
|
AUTOFILL_PROFILE_PATH=$HOME/secrets/dist_beta_autofill.mobileprovision
|
||||||
|
BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden.mobileprovision
|
||||||
|
EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_extension.mobileprovision
|
||||||
|
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_share_extension.mobileprovision
|
||||||
|
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app.mobileprovision
|
||||||
|
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_beta_bitwarden_watch_app_extension.mobileprovision
|
||||||
|
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||||
|
|
||||||
|
mkdir -p "$PROFILES_DIR_PATH"
|
||||||
|
|
||||||
|
AUTOFILL_UUID=$(grep UUID -A1 -a $AUTOFILL_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $AUTOFILL_PROFILE_PATH "$PROFILES_DIR_PATH/$AUTOFILL_UUID.mobileprovision"
|
||||||
|
|
||||||
|
BITWARDEN_UUID=$(grep UUID -A1 -a $BITWARDEN_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $BITWARDEN_PROFILE_PATH "$PROFILES_DIR_PATH/$BITWARDEN_UUID.mobileprovision"
|
||||||
|
|
||||||
|
EXTENSION_UUID=$(grep UUID -A1 -a $EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$EXTENSION_UUID.mobileprovision"
|
||||||
|
|
||||||
|
SHARE_EXTENSION_UUID=$(grep UUID -A1 -a $SHARE_EXTENSION_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $SHARE_EXTENSION_PROFILE_PATH "$PROFILES_DIR_PATH/$SHARE_EXTENSION_UUID.mobileprovision"
|
||||||
|
|
||||||
|
WATCH_APP_UUID=$(grep UUID -A1 -a $WATCH_APP_PROFILE_PATH | grep -io "[-A-F0-9]\{36\}")
|
||||||
|
cp $WATCH_APP_PROFILE_PATH "$PROFILES_DIR_PATH/$WATCH_APP_UUID.mobileprovision"
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
- name: Restore packages
|
||||||
|
run: |
|
||||||
|
dotnet restore
|
||||||
|
dotnet tool restore
|
||||||
|
|
||||||
|
- name: Setup iOS build CAKE (Testing)
|
||||||
|
run: dotnet cake build.cake --target iOS --variant beta
|
||||||
|
|
||||||
|
- name: Bulid WatchApp
|
||||||
|
run: |
|
||||||
|
echo "##### Build WatchApp with Release Configuration"
|
||||||
|
xcodebuild archive -workspace ./src/watchOS/bitwarden/bitwarden.xcodeproj/project.xcworkspace -configuration Release -scheme bitwarden\ WatchKit\ App -archivePath ./src/watchOS/bitwarden
|
||||||
|
|
||||||
|
echo "##### Done"
|
||||||
|
|
||||||
|
- name: Archive Build for App Store
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Write-Output "##### Archive for Release ios-arm64"
|
||||||
|
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
|
||||||
|
|
||||||
|
Write-Output "##### Done"
|
||||||
|
|
||||||
|
- name: Archive Build for Mobile Automation
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Write-Output "##### Archive Debug for iossimulator-x64"
|
||||||
|
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
|
||||||
|
|
||||||
|
Write-Output "##### Done"
|
||||||
|
ls ~/Library/Developer/Xcode/Archives
|
||||||
|
|
||||||
|
- name: Export .ipa for App Store
|
||||||
|
env:
|
||||||
|
EXPORT_OPTIONS_PATH: ./.github/resources/export-options-app-store.plist
|
||||||
|
EXPORT_PATH: ./bitwarden-export
|
||||||
|
run: |
|
||||||
|
ARCHIVE_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive"
|
||||||
|
|
||||||
|
xcodebuild -exportArchive -archivePath $ARCHIVE_PATH -exportPath $EXPORT_PATH \
|
||||||
|
-exportOptionsPlist $EXPORT_OPTIONS_PATH
|
||||||
|
|
||||||
|
- 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: |
|
||||||
|
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
|
||||||
|
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
|
||||||
|
|
||||||
|
- name: Show Bitwarden Export
|
||||||
|
shell: bash
|
||||||
|
run: ls -a -R ./bitwarden-export
|
||||||
|
|
||||||
|
- 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: |
|
||||||
|
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
|
||||||
|
|
||||||
|
cp -r -v $ARCHIVE_DSYMS_PATH $EXPORT_PATH
|
||||||
|
mkdir $WATCH_DSYMS_EXPORT_PATH
|
||||||
|
cp -r -v $WATCH_ARCHIVE_DSYMS_PATH $WATCH_DSYMS_EXPORT_PATH
|
||||||
|
|
||||||
|
- name: Upload App Store .ipa & dSYMs artifacts
|
||||||
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||||
|
with:
|
||||||
|
name: Bitwarden iOS
|
||||||
|
path: |
|
||||||
|
./bitwarden-export/Bitwarden*.ipa
|
||||||
|
./bitwarden-export/dSYMs/*.*
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload .app file for Automation CI
|
||||||
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||||
|
with:
|
||||||
|
name: ${{ env.app_ci_output_filename }}.app.zip
|
||||||
|
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Install AppCenter CLI
|
||||||
|
run: npm install -g appcenter-cli
|
||||||
|
|
||||||
|
- name: Upload dSYMs to App Center
|
||||||
|
env:
|
||||||
|
APPCENTER_IOS_TOKEN: ${{ steps.retrieve-secrets.outputs.appcenter-ios-token }}
|
||||||
|
run: appcenter crashes upload-symbols -a bitwarden/bitwarden -s "./bitwarden-export/dSYMs" --token $APPCENTER_IOS_TOKEN
|
||||||
|
|
||||||
|
- name: Upload Watch dSYMs to Firebase Crashlytics
|
||||||
|
run: |
|
||||||
|
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" \;
|
||||||
|
|
||||||
|
- name: Validate app in App Store
|
||||||
|
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 Beta.ipa" \
|
||||||
|
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Deploy to App Store
|
||||||
|
env:
|
||||||
|
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
|
||||||
|
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||||
|
run: |
|
||||||
|
xcrun altool --upload-app --type ios --file "./bitwarden-export/Bitwarden Beta.ipa" \
|
||||||
|
--username "$APPLE_ID_USERNAME" --password "$APPLE_ID_PASSWORD"
|
||||||
|
|
||||||
|
check-failures:
|
||||||
|
name: Check for failures
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs:
|
||||||
|
- setup
|
||||||
|
- ios
|
||||||
|
steps:
|
||||||
|
- name: Check if any job failed
|
||||||
|
if: |
|
||||||
|
(github.ref == 'refs/heads/main'
|
||||||
|
|| github.ref == 'refs/heads/rc'
|
||||||
|
|| github.ref == 'refs/heads/hotfix-rc')
|
||||||
|
&& contains(needs.*.result, 'failure')
|
||||||
|
run: exit 1
|
||||||
|
|
||||||
|
- name: Login to Azure - CI Subscription
|
||||||
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
|
- name: Retrieve secrets
|
||||||
|
id: retrieve-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
if: failure()
|
||||||
|
with:
|
||||||
|
keyvault: "bitwarden-ci"
|
||||||
|
secrets: "devops-alerts-slack-webhook-url"
|
||||||
|
|
||||||
|
- name: Notify Slack on failure
|
||||||
|
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
|
||||||
|
if: failure()
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||||
|
with:
|
||||||
|
status: ${{ job.status }}
|
||||||
555
.github/workflows/build.yml
vendored
555
.github/workflows/build.yml
vendored
@@ -10,13 +10,18 @@ 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
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Set up CLOC
|
- name: Set up CLOC
|
||||||
run: |
|
run: |
|
||||||
@@ -35,7 +40,7 @@ jobs:
|
|||||||
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
|
hotfix_branch_exists: ${{ steps.branch-check.outputs.hotfix_branch_exists }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
@@ -63,19 +68,27 @@ 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: 5.9.0
|
nuget-version: 6.4.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: '3.1.x'
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
- name: Set up MSBuild
|
- name: Set up MSBuild
|
||||||
uses: microsoft/setup-msbuild@031090342aeefe171e49f3820f3b52110c66e402 # v1.3.2
|
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
|
||||||
|
|
||||||
|
# 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
|
||||||
@@ -83,7 +96,8 @@ 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*' | Select -First 1 -ExpandProperty FullName)" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
|
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
|
||||||
Write-Output "Java Home: $env:JAVA_HOME"
|
Write-Output "Java Home: $env:JAVA_HOME"
|
||||||
|
|
||||||
- name: Print environment
|
- name: Print environment
|
||||||
@@ -95,43 +109,47 @@ jobs:
|
|||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Decrypt secrets
|
- name: Login to Azure - CI Subscription
|
||||||
env:
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
with:
|
||||||
run: |
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
mkdir -p ~/secrets
|
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
- name: Download secrets
|
||||||
--output ./src/Android/app_play-keystore.jks ./.github/secrets/app_play-keystore.jks.gpg
|
env:
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
ACCOUNT_NAME: bitwardenci
|
||||||
--output ./src/Android/app_upload-keystore.jks ./.github/secrets/app_upload-keystore.jks.gpg
|
CONTAINER_NAME: mobile
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
run: |
|
||||||
--output $HOME/secrets/play_creds.json ./.github/secrets/play_creds.json.gpg
|
mkdir -p $HOME/secrets
|
||||||
|
|
||||||
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||||
|
--name app_play-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_play-keystore.jks --output none
|
||||||
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||||
|
--name app_upload-keystore.jks --file ./${{ env.android_folder_path_bash }}/app_upload-keystore.jks --output none
|
||||||
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||||
|
--name play_creds.json --file $HOME/secrets/play_creds.json --output none
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Decrypt secrets - Google Services
|
- name: Download secrets - Google Services
|
||||||
if: ${{ matrix.variant == 'prod' }}
|
if: ${{ matrix.variant == 'prod' }}
|
||||||
env:
|
env:
|
||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
ACCOUNT_NAME: bitwardenci
|
||||||
|
CONTAINER_NAME: mobile
|
||||||
run: |
|
run: |
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||||
--output ./src/Android/google-services.json ./.github/secrets/google-services.json.gpg
|
--name google-services.json --file ./${{ env.android_folder_path_bash }}/google-services.json --output none
|
||||||
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 "##### Setting Android Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
|
||||||
echo "########################################"
|
|
||||||
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\"/" \
|
||||||
./src/Android/Properties/AndroidManifest.xml
|
./${{ env.android_folder_path_bash }}/AndroidManifest.xml
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Restore packages
|
- name: Restore packages
|
||||||
@@ -140,87 +158,75 @@ jobs:
|
|||||||
- name: Restore tools
|
- name: Restore tools
|
||||||
run: dotnet tool restore
|
run: dotnet tool restore
|
||||||
|
|
||||||
- name: Verify Format
|
# - name: Run Core tests
|
||||||
run: dotnet tool run dotnet-format --check
|
# run: |
|
||||||
|
# dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx" `
|
||||||
|
# /p:CustomConstants=UT
|
||||||
|
|
||||||
- name: Run Core tests
|
# - name: Report test results
|
||||||
run: dotnet test test/Core.Test/Core.Test.csproj --logger "trx;LogFileName=test-results.trx"
|
# uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0
|
||||||
|
# if: always()
|
||||||
- name: Report test results
|
# with:
|
||||||
uses: dorny/test-reporter@eaa763f6ffc21c7a37837f56cd5f9737f27fc6c8 # v1.8.0
|
# name: Test Results
|
||||||
if: always()
|
# path: "**/test-results.trx"
|
||||||
with:
|
# reporter: dotnet-trx
|
||||||
name: Test Results
|
# fail-on-error: true
|
||||||
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 Android
|
- name: Build & Sign 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: |
|
||||||
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
|
$projToBuild = "$($env:GITHUB_WORKSPACE)/${{ env.main_app_project_path }}";
|
||||||
$packageName = "com.x8bit.bitwarden";
|
$packageName = "com.x8bit.bitwarden";
|
||||||
|
|
||||||
if ("${{ matrix.variant }}" -ne "prod")
|
if ("${{ matrix.variant }}" -ne "prod")
|
||||||
{
|
{
|
||||||
$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 "########################################"
|
|
||||||
|
|
||||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
$signingUploadKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_upload-keystore.jks"
|
||||||
"/p:AndroidSigningKeyAlias=upload" "/p:AndroidSigningKeyPass=$($env:UPLOAD_KEYSTORE_PASSWORD)" `
|
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android `
|
||||||
"/p:AndroidSigningKeyStore=$("app_upload-keystore.jks")" `
|
/p:AndroidPackageFormats=aab `
|
||||||
"/p:AndroidSigningStorePass=$($env:UPLOAD_KEYSTORE_PASSWORD)" "/p:AndroidPackageFormat=aab" "/v:quiet"
|
/p:AndroidKeyStore=true `
|
||||||
|
/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 + "/src/Android/bin/Release/$($packageName)-Signed.aab");
|
$signedAabPath = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_folder_path }}\bin\Release\${{ env.target-net-version }}-android\publish\$($packageName)-Signed.aab";
|
||||||
$signedAabDestPath = $($env:GITHUB_WORKSPACE + "/$($packageName).aab");
|
$signedAabDestPath = "$($env:GITHUB_WORKSPACE)\$($packageName).aab";
|
||||||
Copy-Item $signedAabPath $signedAabDestPath
|
Copy-Item $signedAabPath $signedAabDestPath
|
||||||
|
|
||||||
Write-Output "########################################"
|
|
||||||
Write-Output "##### Sign APK Release Configuration"
|
Write-Output "##### Sign APK Release Configuration"
|
||||||
Write-Output "########################################"
|
|
||||||
|
|
||||||
msbuild "$($androidPath)" "/t:SignAndroidPackage" "/p:Configuration=Release" "/p:AndroidKeyStore=true" `
|
$signingPlayKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_play-keystore.jks"
|
||||||
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:PLAY_KEYSTORE_PASSWORD)" `
|
dotnet publish $projToBuild -c Release -f ${{ env.target-net-version }}-android `
|
||||||
"/p:AndroidSigningKeyStore=$("app_play-keystore.jks")" `
|
/p:AndroidKeyStore=true `
|
||||||
"/p:AndroidSigningStorePass=$($env:PLAY_KEYSTORE_PASSWORD)" "/v:quiet"
|
/p:AndroidSigningKeyStore=$signingPlayKeyStore `
|
||||||
|
/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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||||
with:
|
with:
|
||||||
name: com.x8bit.bitwarden.aab
|
name: com.x8bit.bitwarden.aab
|
||||||
path: ./com.x8bit.bitwarden.aab
|
path: ./com.x8bit.bitwarden.aab
|
||||||
@@ -228,7 +234,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Prod .apk artifact
|
- name: Upload Prod .apk artifact
|
||||||
if: ${{ matrix.variant == 'prod' }}
|
if: ${{ matrix.variant == 'prod' }}
|
||||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||||
with:
|
with:
|
||||||
name: com.x8bit.bitwarden.apk
|
name: com.x8bit.bitwarden.apk
|
||||||
path: ./com.x8bit.bitwarden.apk
|
path: ./com.x8bit.bitwarden.apk
|
||||||
@@ -236,7 +242,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Other .apk artifact
|
- name: Upload Other .apk artifact
|
||||||
if: ${{ matrix.variant != 'prod' }}
|
if: ${{ matrix.variant != 'prod' }}
|
||||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.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
|
||||||
@@ -256,7 +262,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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.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
|
||||||
@@ -264,7 +270,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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.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
|
||||||
@@ -277,26 +283,39 @@ 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: |
|
||||||
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/netcoreapp3.1/Publisher.dll"
|
$publisherPath = "$($env:GITHUB_WORKSPACE)\store\google\Publisher\bin\Release\net8.0\Publisher.dll"
|
||||||
CREDS_PATH="$HOME/secrets/play_creds.json"
|
$credsPath = "$($HOME)\secrets\play_creds.json"
|
||||||
AAB_PATH="$GITHUB_WORKSPACE/com.x8bit.bitwarden.aab"
|
$aabPath = "$($env:GITHUB_WORKSPACE)\com.x8bit.bitwarden.aab"
|
||||||
TRACK="internal"
|
$track = "internal"
|
||||||
|
|
||||||
dotnet $PUBLISHER_PATH $CREDS_PATH $AAB_PATH $TRACK
|
dotnet $publisherPath $credsPath $aabPath $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_folder_path_bash: src/App/Platforms/Android
|
||||||
|
android_manifest_path: src/App/Platforms/Android/AndroidManifest.xml
|
||||||
steps:
|
steps:
|
||||||
- name: Setup NuGet
|
- name: Setup NuGet
|
||||||
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
uses: nuget/setup-nuget@296fd3ccf8528660c91106efefe2364482f86d6f # v1.2.0
|
||||||
with:
|
with:
|
||||||
nuget-version: 5.9.0
|
nuget-version: 6.4.0
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
- name: Set up MSBuild
|
- name: Set up MSBuild
|
||||||
uses: microsoft/setup-msbuild@031090342aeefe171e49f3820f3b52110c66e402 # v1.3.2
|
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2.0.0
|
||||||
|
|
||||||
|
# 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
|
||||||
@@ -316,56 +335,44 @@ jobs:
|
|||||||
echo "GitHub event: $GITHUB_EVENT"
|
echo "GitHub event: $GITHUB_EVENT"
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Decrypt secrets
|
- name: Login to Azure - CI Subscription
|
||||||
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
|
- name: Download secrets
|
||||||
env:
|
env:
|
||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
ACCOUNT_NAME: bitwardenci
|
||||||
|
CONTAINER_NAME: mobile
|
||||||
|
FILE: app_fdroid-keystore.jks
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/secrets
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||||
|
--file ${{ env.android_folder_path_bash }}/$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 "##### Setting F-Droid Version Code to $BUILD_NUMBER" | tee -a $GITHUB_STEP_SUMMARY
|
||||||
echo "########################################"
|
|
||||||
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\"/" \
|
||||||
./src/Android/Properties/AndroidManifest.xml
|
./${{ env.android_manifest_path }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Clean for F-Droid
|
- name: Clean for F-Droid
|
||||||
run: |
|
run: |
|
||||||
$androidPath = $($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj");
|
$directoryBuildProps = $($env:GITHUB_WORKSPACE + "/Directory.Build.props");
|
||||||
$appPath = $($env:GITHUB_WORKSPACE + "/src/App/App.csproj");
|
|
||||||
$corePath = $($env:GITHUB_WORKSPACE + "/src/Core/Core.csproj");
|
|
||||||
|
|
||||||
$androidManifest = $($env:GITHUB_WORKSPACE + "/src/Android/Properties/AndroidManifest.xml");
|
$androidManifest = $($env:GITHUB_WORKSPACE + "/${{ env.android_manifest_path }}");
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "##### Back up project files"
|
||||||
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 $directoryBuildProps $($directoryBuildProps + ".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);
|
||||||
@@ -375,80 +382,39 @@ jobs:
|
|||||||
|
|
||||||
$xml.Save($androidManifest);
|
$xml.Save($androidManifest);
|
||||||
|
|
||||||
Write-Output "########################################"
|
Write-Output "##### Enabling FDROID constant"
|
||||||
Write-Output "##### Uninstall from Android.csproj"
|
|
||||||
Write-Output "########################################"
|
|
||||||
|
|
||||||
$xml=New-Object XML;
|
(Get-Content $directoryBuildProps).Replace('<!-- <CustomConstants>FDROID</CustomConstants> -->', '<CustomConstants>FDROID</CustomConstants>') | Set-Content $directoryBuildProps
|
||||||
$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: nuget restore
|
run: dotnet restore
|
||||||
|
|
||||||
- name: Build for F-Droid
|
- name: Build & Sign F-Droid
|
||||||
run: |
|
|
||||||
$configuration = "FDroid";
|
|
||||||
|
|
||||||
Write-Output "########################################"
|
|
||||||
Write-Output "##### Build $configuration Configuration"
|
|
||||||
Write-Output "########################################"
|
|
||||||
|
|
||||||
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" "/p:Configuration=$configuration"
|
|
||||||
|
|
||||||
- name: Sign for F-Droid
|
|
||||||
env:
|
env:
|
||||||
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
|
FDROID_KEYSTORE_PASSWORD: ${{ secrets.FDROID_KEYSTORE_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
Write-Output "########################################"
|
$projToBuild = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_project_path }}";
|
||||||
Write-Output "##### Sign FDroid Configuration"
|
$packageName = "com.x8bit.bitwarden";
|
||||||
Write-Output "########################################"
|
|
||||||
|
|
||||||
msbuild "$($env:GITHUB_WORKSPACE + "/src/Android/Android.csproj")" `
|
Write-Output "##### Sign FDroid"
|
||||||
"/t:SignAndroidPackage" "/p:Configuration=FDroid" "/p:AndroidKeyStore=true" `
|
|
||||||
"/p:AndroidSigningKeyAlias=bitwarden" "/p:AndroidSigningKeyPass=$($env:FDROID_KEYSTORE_PASSWORD)" `
|
$signingFdroidKeyStore = "$($env:GITHUB_WORKSPACE)\${{ env.android_folder_path }}\app_fdroid-keystore.jks"
|
||||||
"/p:AndroidSigningKeyStore=$("app_fdroid-keystore.jks")" `
|
dotnet build $projToBuild -c Release -f ${{ env.target-net-version }}-android `
|
||||||
"/p:AndroidSigningStorePass=$($env:FDROID_KEYSTORE_PASSWORD)" "/v:quiet"
|
/p:AndroidKeyStore=true `
|
||||||
|
/p:AndroidSigningKeyStore=$signingFdroidKeyStore `
|
||||||
|
/p:AndroidSigningKeyAlias=bitwarden `
|
||||||
|
/p:AndroidSigningKeyPass="$($env:FDROID_KEYSTORE_PASSWORD)" `
|
||||||
|
/p:AndroidSigningStorePass="$($env:FDROID_KEYSTORE_PASSWORD)" ` --no-restore
|
||||||
|
|
||||||
Write-Output "########################################"
|
|
||||||
Write-Output "##### Copy FDroid apk to project root"
|
Write-Output "##### Copy FDroid apk to project root"
|
||||||
Write-Output "########################################"
|
|
||||||
|
|
||||||
$signedApkPath = $($env:GITHUB_WORKSPACE + "/src/Android/bin/FDroid/com.x8bit.bitwarden-Signed.apk");
|
$signedApkPath = "$($env:GITHUB_WORKSPACE)\${{ env.main_app_folder_path }}\bin\Release\${{ env.target-net-version }}-android\$($packageName)-Signed.apk";
|
||||||
$signedApkDestPath = $($env:GITHUB_WORKSPACE + "/com.x8bit.bitwarden-fdroid.apk");
|
$signedApkDestPath = "$($env:GITHUB_WORKSPACE)\com.x8bit.bitwarden-fdroid.apk";
|
||||||
|
|
||||||
Copy-Item $signedApkPath $signedApkDestPath
|
Copy-Item $signedApkPath $signedApkDestPath
|
||||||
|
|
||||||
- name: Upload F-Droid .apk artifact
|
- name: Upload F-Droid .apk artifact
|
||||||
uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.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
|
||||||
@@ -460,7 +426,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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.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
|
||||||
@@ -469,24 +435,42 @@ jobs:
|
|||||||
|
|
||||||
ios:
|
ios:
|
||||||
name: Apple iOS
|
name: Apple iOS
|
||||||
runs-on: macos-12
|
runs-on: macos-14
|
||||||
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: 5.9.0
|
nuget-version: 6.4.0
|
||||||
|
|
||||||
|
- name: Set up .NET
|
||||||
|
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.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"
|
||||||
|
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
@@ -502,71 +486,71 @@ jobs:
|
|||||||
keyvault: "bitwarden-ci"
|
keyvault: "bitwarden-ci"
|
||||||
secrets: "appcenter-ios-token"
|
secrets: "appcenter-ios-token"
|
||||||
|
|
||||||
- name: Decrypt secrets
|
- name: Download Provisioning Profiles secrets
|
||||||
env:
|
env:
|
||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
ACCOUNT_NAME: bitwardenci
|
||||||
|
CONTAINER_NAME: profiles
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/secrets
|
mkdir -p $HOME/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"
|
||||||
|
)
|
||||||
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
for FILE in "${profiles[@]}"
|
||||||
--output $HOME/secrets/bitwarden-mobile-key.p12 ./.github/secrets/bitwarden-mobile-key.p12.gpg
|
do
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||||
--output $HOME/secrets/iphone-distribution-cert.p12 ./.github/secrets/iphone-distribution-cert.p12.gpg
|
--file $HOME/secrets/$FILE --output none
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
done
|
||||||
--output $HOME/secrets/dist_autofill.mobileprovision ./.github/secrets/dist_autofill.mobileprovision.gpg
|
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
- name: Download Google Services secret
|
||||||
--output $HOME/secrets/dist_bitwarden.mobileprovision ./.github/secrets/dist_bitwarden.mobileprovision.gpg
|
env:
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
ACCOUNT_NAME: bitwardenci
|
||||||
--output $HOME/secrets/dist_extension.mobileprovision ./.github/secrets/dist_extension.mobileprovision.gpg
|
CONTAINER_NAME: mobile
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
FILE: GoogleService-Info.plist
|
||||||
--output $HOME/secrets/dist_share_extension.mobileprovision \
|
run: |
|
||||||
./.github/secrets/dist_share_extension.mobileprovision.gpg
|
mkdir -p $HOME/secrets
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME --name $FILE \
|
||||||
--output $HOME/secrets/dist_watch_app.mobileprovision \
|
--file src/watchOS/bitwarden/$FILE --output none
|
||||||
./.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 "##### Setting iOS CFBundleVersion to $BUILD_NUMBER" | tee -a $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
|
||||||
echo "##### Setting CFBundleVersion $BUILD_NUMBER"
|
|
||||||
echo "########################################"
|
|
||||||
|
|
||||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./src/iOS/Info.plist
|
|
||||||
perl -0777 -pi.bak -e 's/<key>CFBundleVersion<\/key>\s*<string>1<\/string>/<key>CFBundleVersion<\/key>\n\t<string>'"$BUILD_NUMBER"'<\/string>/' ./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"
|
||||||
echo "########################################"
|
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
|
||||||
|
|
||||||
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
|
- name: Get certificates
|
||||||
|
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 \
|
|
||||||
-T /usr/bin/codesign -T /usr/bin/security
|
security import $HOME/certificates/ios-distribution.p12 -k build.keychain -P "" -T /usr/bin/codesign \
|
||||||
security import ~/secrets/iphone-distribution-cert.p12 -k build.keychain -P $DIST_CERT_PASSWORD \
|
-T /usr/bin/security
|
||||||
-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
|
||||||
@@ -575,8 +559,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_watch_app.mobileprovision
|
WATCH_APP_PROFILE_PATH=$HOME/secrets/dist_bitwarden_watch_app.mobileprovision
|
||||||
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_watch_app_extension.mobileprovision
|
WATCH_APP_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_bitwarden_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"
|
||||||
@@ -599,85 +583,55 @@ 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: |
|
||||||
$configuration = "AppStore";
|
echo "##### Archive for Release ios-arm64"
|
||||||
$platform = "iPhone";
|
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
|
||||||
|
|
||||||
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: |
|
||||||
$configuration = "Release";
|
echo "##### Archive Debug for iossimulator-x64"
|
||||||
$platform = "iPhoneSimulator";
|
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
|
||||||
|
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: |
|
||||||
ARCHIVE_PATH="./src/iOS/bin/iPhoneSimulator/Release/BitwardeniOS.app"
|
zip -r -q ${{ env.app_ci_output_filename }}.app.zip $ARCHIVE_PATH
|
||||||
EXPORT_PATH="./bitwarden-export"
|
mv ${{ env.app_ci_output_filename }}.app.zip $EXPORT_PATH
|
||||||
|
|
||||||
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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||||
with:
|
with:
|
||||||
name: Bitwarden iOS
|
name: Bitwarden iOS
|
||||||
path: |
|
path: |
|
||||||
@@ -686,10 +640,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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
|
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||||
with:
|
with:
|
||||||
name: BitwardeniOS.app.zip
|
name: ${{ env.app_ci_output_filename }}.app.zip
|
||||||
path: ./bitwarden-export/BitwardeniOS.app.zip
|
path: ./bitwarden-export/${{ env.app_ci_output_filename }}.app.zip
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Install AppCenter CLI
|
- name: Install AppCenter CLI
|
||||||
@@ -720,12 +674,23 @@ 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"
|
||||||
echo "########################################"
|
|
||||||
|
|
||||||
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" \;
|
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" \;
|
||||||
|
|
||||||
|
- name: Validate app in App Store
|
||||||
|
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: |
|
||||||
(github.ref == 'refs/heads/main'
|
(github.ref == 'refs/heads/main'
|
||||||
@@ -753,7 +718,7 @@ jobs:
|
|||||||
_CROWDIN_PROJECT_ID: "269690"
|
_CROWDIN_PROJECT_ID: "269690"
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
@@ -768,13 +733,13 @@ jobs:
|
|||||||
secrets: "crowdin-api-token"
|
secrets: "crowdin-api-token"
|
||||||
|
|
||||||
- name: Upload Sources
|
- name: Upload Sources
|
||||||
uses: crowdin/github-action@6fb7e99759b996fd142995636fd8c88c1fb8ecd9 # v1.16.1
|
uses: crowdin/github-action@67705afb6985401459cd143d5f5f00c9dc212f23 # v1.20.2
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||||
with:
|
with:
|
||||||
config: crowdin.yml
|
config: crowdin.yml
|
||||||
crowdin_branch_name: main
|
crowdin_branch_name: main
|
||||||
upload_sources: true
|
upload_sources: true
|
||||||
upload_translations: false
|
upload_translations: false
|
||||||
|
|
||||||
@@ -792,27 +757,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Check if any job failed
|
- name: Check if any job failed
|
||||||
if: |
|
if: |
|
||||||
(github.ref == 'refs/heads/main')
|
(github.ref == 'refs/heads/main'
|
||||||
|| (github.ref == 'refs/heads/rc')
|
|| github.ref == 'refs/heads/rc'
|
||||||
|| (github.ref == 'refs/heads/hotfix-rc')
|
|| github.ref == 'refs/heads/hotfix-rc')
|
||||||
env:
|
&& contains(needs.*.result, 'failure')
|
||||||
CLOC_STATUS: ${{ needs.cloc.result }}
|
run: exit 1
|
||||||
ANDROID_STATUS: ${{ needs.android.result }}
|
|
||||||
F_DROID_STATUS: ${{ needs.f-droid.result }}
|
|
||||||
IOS_STATUS: ${{ needs.ios.result }}
|
|
||||||
CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }}
|
|
||||||
run: |
|
|
||||||
if [ "$CLOC_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$ANDROID_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$F_DROID_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$IOS_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
elif [ "$CROWDIN_PUSH_STATUS" = "failure" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
@@ -829,7 +778,7 @@ jobs:
|
|||||||
secrets: "devops-alerts-slack-webhook-url"
|
secrets: "devops-alerts-slack-webhook-url"
|
||||||
|
|
||||||
- name: Notify Slack on failure
|
- name: Notify Slack on failure
|
||||||
uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0
|
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
|
||||||
if: failure()
|
if: failure()
|
||||||
env:
|
env:
|
||||||
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}
|
||||||
|
|||||||
53
.github/workflows/cleanup-rc-branch.yml
vendored
Normal file
53
.github/workflows/cleanup-rc-branch.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
name: Cleanup RC Branch
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v**
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
delete-rc:
|
||||||
|
name: Delete RC Branch
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- name: Login to Azure - CI Subscription
|
||||||
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
|
- name: Retrieve bot secrets
|
||||||
|
id: retrieve-bot-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
with:
|
||||||
|
keyvault: bitwarden-ci
|
||||||
|
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||||
|
|
||||||
|
- name: Checkout main
|
||||||
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
token: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
||||||
|
|
||||||
|
- name: Check if a RC branch exists
|
||||||
|
id: branch-check
|
||||||
|
run: |
|
||||||
|
hotfix_rc_branch_check=$(git ls-remote --heads origin hotfix-rc | wc -l)
|
||||||
|
rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
|
||||||
|
|
||||||
|
if [[ "${hotfix_rc_branch_check}" -gt 0 ]]; then
|
||||||
|
echo "hotfix-rc branch exists." | tee -a $GITHUB_STEP_SUMMARY
|
||||||
|
echo "name=hotfix-rc" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${rc_branch_check}" -gt 0 ]]; then
|
||||||
|
echo "rc branch exists." | tee -a $GITHUB_STEP_SUMMARY
|
||||||
|
echo "name=rc" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Delete RC branch
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ steps.branch-check.outputs.name }}
|
||||||
|
run: |
|
||||||
|
if ! [[ -z "$BRANCH_NAME" ]]; then
|
||||||
|
git push --quiet origin --delete $BRANCH_NAME
|
||||||
|
echo "Deleted $BRANCH_NAME branch." | tee -a $GITHUB_STEP_SUMMARY
|
||||||
|
fi
|
||||||
4
.github/workflows/crowdin-pull.yml
vendored
4
.github/workflows/crowdin-pull.yml
vendored
@@ -15,7 +15,7 @@ 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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
@@ -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@6fb7e99759b996fd142995636fd8c88c1fb8ecd9 # v1.16.1
|
uses: crowdin/github-action@67705afb6985401459cd143d5f5f00c9dc212f23 # v1.20.2
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }}
|
||||||
|
|||||||
2
.github/workflows/pr-labeler.yml
vendored
2
.github/workflows/pr-labeler.yml
vendored
@@ -12,6 +12,6 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/labeler@ac9175f8a1f3625fd0d4fb234536d26811351594 # v4.3.0
|
- uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0
|
||||||
with:
|
with:
|
||||||
sync-labels: true
|
sync-labels: true
|
||||||
|
|||||||
62
.github/workflows/release.yml
vendored
62
.github/workflows/release.yml
vendored
@@ -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: github.event.inputs.release_type != 'Dry Run'
|
if: 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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- 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: ${{ github.event.inputs.release_type }}
|
release-type: ${{ inputs.release_type }}
|
||||||
project-type: xamarin
|
project-type: xamarin
|
||||||
file: src/Android/Properties/AndroidManifest.xml
|
file: src/App/Platforms/Android/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: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
uses: chrnorm/deployment-action@d42cde7132fcec920de534fffc3be83794335c00 # v2.0.5
|
uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7
|
||||||
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: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||||
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: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
if: ${{ inputs.release_type == 'Dry Run' }}
|
||||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||||
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: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
uses: ncipollo/release-action@6c75be85e571768fa31b40abf38de58ba0397db5 # v1.13.0
|
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.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: ${{ github.event.inputs.release_type != 'Dry Run' && success() }}
|
if: ${{ inputs.release_type != 'Dry Run' && success() }}
|
||||||
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
|
uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3
|
||||||
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: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }}
|
if: ${{ inputs.release_type != 'Dry Run' && failure() }}
|
||||||
uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1
|
uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3
|
||||||
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@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Download F-Droid .apk artifact
|
- name: Download F-Droid .apk artifact
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||||
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: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
if: ${{ inputs.release_type == 'Dry Run' }}
|
||||||
uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e # v2.28.0
|
uses: dawidd6/action-download-artifact@09f2f74827fd3a8607589e5ad7f9398816f540fe # v3.1.4
|
||||||
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@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
|
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: '16.x'
|
node-version: '16.x'
|
||||||
|
|
||||||
@@ -176,13 +176,19 @@ jobs:
|
|||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
- name: Decrypt secrets
|
- name: Login to Azure - CI Subscription
|
||||||
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
|
- name: Download secrets
|
||||||
env:
|
env:
|
||||||
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
|
ACCOUNT_NAME: bitwardenci
|
||||||
|
CONTAINER_NAME: mobile
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/secrets
|
mkdir -p $HOME/secrets
|
||||||
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
|
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||||
--output ./store/fdroid/keystore.jks ./.github/secrets/store_fdroid-keystore.jks.gpg
|
--name store_fdroid-keystore.jks --file ./store/fdroid/keystore.jks --output none
|
||||||
|
|
||||||
- name: Compile for F-Droid Store
|
- name: Compile for F-Droid Store
|
||||||
env:
|
env:
|
||||||
@@ -211,5 +217,5 @@ jobs:
|
|||||||
cd $GITHUB_WORKSPACE
|
cd $GITHUB_WORKSPACE
|
||||||
|
|
||||||
- name: Deploy to gh-pages
|
- name: Deploy to gh-pages
|
||||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||||
run: npm run deploy
|
run: npm run deploy
|
||||||
|
|||||||
45
.github/workflows/version-auto-bump.yml
vendored
45
.github/workflows/version-auto-bump.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
name: Version Auto Bump
|
name: Auto Bump Mobile Version
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -7,34 +7,25 @@ on:
|
|||||||
- v**
|
- v**
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
setup:
|
bump-version:
|
||||||
name: "Setup"
|
name: Bump Mobile Version
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
outputs:
|
|
||||||
version_number: ${{ steps.version.outputs.new-version }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Branch
|
- name: Login to Azure - CI Subscription
|
||||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
|
with:
|
||||||
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
- name: Calculate bumped version
|
- name: Retrieve bot secrets
|
||||||
id: version
|
id: retrieve-bot-secrets
|
||||||
|
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||||
|
with:
|
||||||
|
keyvault: bitwarden-ci
|
||||||
|
secrets: "github-pat-bitwarden-devops-bot-repo-scope"
|
||||||
|
|
||||||
|
- name: Trigger Version Bump workflow
|
||||||
env:
|
env:
|
||||||
RELEASE_TAG: ${{ github.ref }}
|
GH_TOKEN: ${{ steps.retrieve-bot-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
||||||
run: |
|
run: |
|
||||||
CURR_MAJOR=$(echo $RELEASE_TAG | sed -r 's/refs\/tags\/v([0-9]{4}\.[0-9]{1,2})\.([0-9]{1,2})/\1/')
|
echo '{"cut_rc_branch": "false"}' | \
|
||||||
CURR_PATCH=$(echo $RELEASE_TAG | sed -r 's/refs\/tags\/v([0-9]{4}\.[0-9]{1,2})\.([0-9]{1,2})/\2/')
|
gh workflow run version-bump.yml --json --repo bitwarden/mobile
|
||||||
echo "Current Major: $CURR_MAJOR"
|
|
||||||
echo "Current Patch: $CURR_PATCH"
|
|
||||||
|
|
||||||
NEW_PATCH=$((CURR_PATCH+1))
|
|
||||||
NEW_VER=$CURR_MAJOR.$NEW_PATCH
|
|
||||||
echo "New Version: $NEW_VER"
|
|
||||||
echo "new-version=$NEW_VER" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
trigger_version_bump:
|
|
||||||
name: Bump version to ${{ needs.setup.outputs.version_number }}
|
|
||||||
needs: setup
|
|
||||||
uses: ./.github/workflows/version-bump.yml
|
|
||||||
with:
|
|
||||||
version_number: ${{ needs.setup.outputs.version_number }}
|
|
||||||
secrets: inherit
|
|
||||||
|
|||||||
195
.github/workflows/version-bump.yml
vendored
195
.github/workflows/version-bump.yml
vendored
@@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
name: Version Bump
|
name: Version Bump
|
||||||
run-name: Version Bump - v${{ inputs.version_number }}
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version_number:
|
version_number_override:
|
||||||
description: "New version (example: '2024.1.0')"
|
description: "New version override (leave blank for automatic calculation, example: '2024.1.0')"
|
||||||
required: true
|
required: false
|
||||||
|
type: string
|
||||||
cut_rc_branch:
|
cut_rc_branch:
|
||||||
description: "Cut RC branch?"
|
description: "Cut RC branch?"
|
||||||
default: true
|
default: true
|
||||||
@@ -15,13 +15,36 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
bump_version:
|
bump_version:
|
||||||
name: "Bump Version to v${{ inputs.version_number }}"
|
name: Bump Version
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.set-final-version-output.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
|
- name: Validate version input
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
uses: bitwarden/gh-actions/version-check@main
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
|
- name: Checkout Branch
|
||||||
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
with:
|
||||||
|
ref: main
|
||||||
|
|
||||||
|
- 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: Login to Azure - CI Subscription
|
- name: Login to Azure - CI Subscription
|
||||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||||
with:
|
with:
|
||||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||||
|
|
||||||
- name: Retrieve secrets
|
- name: Retrieve secrets
|
||||||
id: retrieve-secrets
|
id: retrieve-secrets
|
||||||
@@ -32,39 +55,46 @@ jobs:
|
|||||||
github-gpg-private-key-passphrase,
|
github-gpg-private-key-passphrase,
|
||||||
github-pat-bitwarden-devops-bot-repo-scope"
|
github-pat-bitwarden-devops-bot-repo-scope"
|
||||||
|
|
||||||
- name: Checkout Branch
|
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
|
||||||
with:
|
|
||||||
ref: main
|
|
||||||
repository: bitwarden/mobile
|
|
||||||
|
|
||||||
- name: Import GPG key
|
- name: Import GPG key
|
||||||
uses: crazy-max/ghaction-import-gpg@d6f3f49f3345e29369fe57596a3ca8f94c4d2ca7 # v5.4.0
|
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.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 }}
|
||||||
git_user_signingkey: true
|
git_user_signingkey: true
|
||||||
git_commit_gpgsign: true
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
|
- name: Setup git
|
||||||
|
run: |
|
||||||
|
git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com"
|
||||||
|
git config --local user.name "bitwarden-devops-bot"
|
||||||
|
|
||||||
- name: Create Version Branch
|
- name: Create Version Branch
|
||||||
id: create-branch
|
id: create-branch
|
||||||
run: |
|
run: |
|
||||||
NAME=version_bump_${{ github.ref_name }}_${{ inputs.version_number }}
|
NAME=version_bump_${{ github.ref_name }}_$(date +"%Y-%m-%d")
|
||||||
git switch -c $NAME
|
git switch -c $NAME
|
||||||
echo "name=$NAME" >> $GITHUB_OUTPUT
|
echo "name=$NAME" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Install xmllint
|
- name: Install xmllint
|
||||||
run: sudo apt install -y libxml2-utils
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libxml2-utils
|
||||||
|
|
||||||
- name: Verify input version
|
- name: Get current version
|
||||||
env:
|
id: current-version
|
||||||
NEW_VERSION: ${{ inputs.version_number }}
|
|
||||||
run: |
|
run: |
|
||||||
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/Android/Properties/AndroidManifest.xml)
|
' src/App/Platforms/Android/AndroidManifest.xml)
|
||||||
|
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Verify input version
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
env:
|
||||||
|
CURRENT_VERSION: ${{ steps.current-version.outputs.version }}
|
||||||
|
NEW_VERSION: ${{ inputs.version_number_override }}
|
||||||
|
run: |
|
||||||
# Error if version has not changed.
|
# Error if version has not changed.
|
||||||
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
|
if [[ "$NEW_VERSION" == "$CURRENT_VERSION" ]]; then
|
||||||
echo "Version has not changed."
|
echo "Version has not changed."
|
||||||
@@ -80,40 +110,93 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Bump Version - Android XML
|
- name: Calculate next release version
|
||||||
uses: bitwarden/gh-actions/version-bump@main
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
id: calculate-next-version
|
||||||
|
uses: bitwarden/gh-actions/version-next@main
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version_number }}
|
version: ${{ steps.current-version.outputs.version }}
|
||||||
file_path: "src/Android/Properties/AndroidManifest.xml"
|
|
||||||
|
|
||||||
- name: Bump Version - iOS.Autofill
|
- name: Bump Version - Android XML - Version Override
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
id: bump-version-override
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "src/App/Platforms/Android/AndroidManifest.xml"
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
|
- name: Bump Version - Android XML - Automatic Calculation
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
id: bump-version-automatic
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "src/App/Platforms/Android/AndroidManifest.xml"
|
||||||
|
version: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Bump Version - iOS.Autofill - Version Override
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
uses: bitwarden/gh-actions/version-bump@main
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version_number }}
|
|
||||||
file_path: "src/iOS.Autofill/Info.plist"
|
file_path: "src/iOS.Autofill/Info.plist"
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
- name: Bump Version - iOS.Extension
|
- name: Bump Version - iOS.Autofill - Automatic Calculation
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "src/iOS.Autofill/Info.plist"
|
||||||
|
version: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Bump Version - iOS.Extension - Version Override
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
uses: bitwarden/gh-actions/version-bump@main
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version_number }}
|
|
||||||
file_path: "src/iOS.Extension/Info.plist"
|
file_path: "src/iOS.Extension/Info.plist"
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
- name: Bump Version - iOS.ShareExtension
|
- name: Bump Version - iOS.Extension - Automatic Calculation
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "src/iOS.Extension/Info.plist"
|
||||||
|
version: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Bump Version - iOS.ShareExtension - Version Override
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
uses: bitwarden/gh-actions/version-bump@main
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version_number }}
|
|
||||||
file_path: "src/iOS.ShareExtension/Info.plist"
|
file_path: "src/iOS.ShareExtension/Info.plist"
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
- name: Bump Version - iOS
|
- name: Bump Version - iOS.ShareExtension - Automatic Calculation
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
uses: bitwarden/gh-actions/version-bump@main
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version_number }}
|
file_path: "src/iOS.ShareExtension/Info.plist"
|
||||||
file_path: "src/iOS/Info.plist"
|
version: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
- name: Setup git
|
- name: Bump Version - iOS - Version Override
|
||||||
|
if: ${{ inputs.version_number_override != '' }}
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "src/App/Platforms/iOS/Info.plist"
|
||||||
|
version: ${{ inputs.version_number_override }}
|
||||||
|
|
||||||
|
- name: Bump Version - iOS - Automatic Calculation
|
||||||
|
if: ${{ inputs.version_number_override == '' }}
|
||||||
|
uses: bitwarden/gh-actions/version-bump@main
|
||||||
|
with:
|
||||||
|
file_path: "src/App/Platforms/iOS/Info.plist"
|
||||||
|
version: ${{ steps.calculate-next-version.outputs.version }}
|
||||||
|
|
||||||
|
- name: Set Job output
|
||||||
|
id: set-final-version-output
|
||||||
run: |
|
run: |
|
||||||
git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com"
|
if [[ "${{ steps.bump-version-override.outcome }}" == "success" ]]; then
|
||||||
git config --local user.name "bitwarden-devops-bot"
|
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
||||||
|
elif [[ "${{ steps.bump-version-automatic.outcome }}" == "success" ]]; then
|
||||||
|
echo "version=${{ steps.calculate-next-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Check if version changed
|
- name: Check if version changed
|
||||||
id: version-changed
|
id: version-changed
|
||||||
@@ -127,7 +210,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Commit files
|
- name: Commit files
|
||||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
run: git commit -m "Bumped version to ${{ inputs.version_number }}" -a
|
run: git commit -m "Bumped version to ${{ steps.set-final-version-output.outputs.version }}" -a
|
||||||
|
|
||||||
- name: Push changes
|
- name: Push changes
|
||||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
@@ -141,7 +224,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
||||||
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
|
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
|
||||||
TITLE: "Bump version to ${{ inputs.version_number }}"
|
TITLE: "Bump version to ${{ steps.set-final-version-output.outputs.version }}"
|
||||||
run: |
|
run: |
|
||||||
PR_URL=$(gh pr create --title "$TITLE" \
|
PR_URL=$(gh pr create --title "$TITLE" \
|
||||||
--base "main" \
|
--base "main" \
|
||||||
@@ -157,16 +240,18 @@ jobs:
|
|||||||
- [X] Other
|
- [X] Other
|
||||||
|
|
||||||
## Objective
|
## Objective
|
||||||
Automated version bump to ${{ inputs.version_number }}")
|
Automated version bump to ${{ steps.set-final-version-output.outputs.version }}")
|
||||||
echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT
|
echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Approve PR
|
- name: Approve PR
|
||||||
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
||||||
run: gh pr review $PR_NUMBER --approve
|
run: gh pr review $PR_NUMBER --approve
|
||||||
|
|
||||||
- name: Merge PR
|
- name: Merge PR
|
||||||
|
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
GH_TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }}
|
||||||
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
||||||
@@ -174,23 +259,37 @@ jobs:
|
|||||||
|
|
||||||
cut_rc:
|
cut_rc:
|
||||||
name: Cut RC branch
|
name: Cut RC branch
|
||||||
needs: bump_version
|
|
||||||
if: ${{ inputs.cut_rc_branch == true }}
|
if: ${{ inputs.cut_rc_branch == true }}
|
||||||
|
needs: bump_version
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Branch
|
- name: Checkout Branch
|
||||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
with:
|
with:
|
||||||
ref: main
|
ref: main
|
||||||
|
|
||||||
- name: Check if RC branch exists
|
- name: Install xmllint
|
||||||
run: |
|
run: |
|
||||||
remote_rc_branch_check=$(git ls-remote --heads origin rc | wc -l)
|
sudo apt-get update
|
||||||
if [[ "${remote_rc_branch_check}" -gt 0 ]]; then
|
sudo apt-get install -y libxml2-utils
|
||||||
echo "Remote RC branch exists."
|
|
||||||
echo "Please delete current RC branch before running again."
|
- name: Verify version has been updated
|
||||||
exit 1
|
env:
|
||||||
fi
|
NEW_VERSION: ${{ needs.bump_version.outputs.version }}
|
||||||
|
run: |
|
||||||
|
# Wait for version to change.
|
||||||
|
while : ; do
|
||||||
|
echo "Waiting for version to be updated..."
|
||||||
|
git pull --force
|
||||||
|
CURRENT_VERSION=$(xmllint --xpath '
|
||||||
|
string(/manifest/@*[local-name()="versionName"
|
||||||
|
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
11
.github/workflows/workflow-linter.yml
vendored
@@ -1,11 +0,0 @@
|
|||||||
---
|
|
||||||
name: Workflow Linter
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- .github/workflows/**
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
call-workflow:
|
|
||||||
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@main
|
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -31,6 +31,7 @@ Components/
|
|||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
!src/lib/x86/
|
!src/lib/x86/
|
||||||
|
!src/App/Platforms/Android/lib/x86/
|
||||||
build/
|
build/
|
||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
@@ -147,6 +148,7 @@ publish/
|
|||||||
|
|
||||||
# NuGet Packages
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
|
!**/Xamarin.AndroidX.Credentials.1.0.0.nupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
# The packages folder can be ignored because of Package Restore
|
||||||
**/packages/*
|
**/packages/*
|
||||||
# except build/, which is used as an MSBuild target.
|
# except build/, which is used as an MSBuild target.
|
||||||
|
|||||||
16
Directory.Build.props
Normal file
16
Directory.Build.props
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<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> -->
|
||||||
|
|
||||||
|
<!-- Uncomment this when building FDROID-->
|
||||||
|
<!-- <CustomConstants>FDROID</CustomConstants> -->
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:master)
|
[](https://github.com/bitwarden/mobile/actions/workflows/build.yml?query=branch:main)
|
||||||
[](https://crowdin.com/project/bitwarden-mobile)
|
[](https://crowdin.com/project/bitwarden-mobile)
|
||||||
[](https://gitter.im/bitwarden/Lobby)
|
[](https://gitter.im/bitwarden/Lobby)
|
||||||
|
|
||||||
@@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
<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# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
|
The Bitwarden mobile application is written in C# using .NET MAUI.
|
||||||
|
|
||||||
<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" />
|
||||||
|
|
||||||
# Build/Run
|
# Build/Run
|
||||||
|
|
||||||
Please refer to the [Mobile section](https://contributing.bitwarden.com/getting-started/clients/mobile/) of the [Contributing Documentation](https://contributing.bitwarden.com/) for build instructions, recommended tooling, code style tips, and lots of other great information to get you started.
|
Please refer to the [Mobile section](https://contributing.bitwarden.com/getting-started/mobile/) of the [Contributing Documentation](https://contributing.bitwarden.com/) for build instructions, recommended tooling, code style tips, and lots of other great information to get you started.
|
||||||
|
|
||||||
# We're Hiring!
|
# We're Hiring!
|
||||||
|
|
||||||
@@ -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 `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.
|
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.
|
||||||
|
|
||||||
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.
|
||||||
|
|||||||
@@ -1,471 +1,233 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 16.0.29009.5
|
VisualStudioVersion = 17.8.34112.27
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android", "src\Android\Android.csproj", "{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{971FDF07-E288-4239-B47A-E9E7E912193B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "App", "src\App\App.csproj", "{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Core", "src\Core\Core.csproj", "{4B8A8C41-9820-4341-974C-41E65B7F4366}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Playground", "test\Playground\Playground.csproj", "{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{D10CA4A9-F866-40E1-B658-F69051236C71}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8904C536-C67D-420F-9971-51B26574C3AA}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD-9047-4C3C-8EA3-D972D6622D84}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{76690DFB-B7F4-4781-83E4-113FDC450AFE}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
.gitignore = .gitignore
|
|
||||||
.github\workflows\build.yml = .github\workflows\build.yml
|
|
||||||
CONTRIBUTING.md = CONTRIBUTING.md
|
|
||||||
crowdin.yml = crowdin.yml
|
|
||||||
README.md = README.md
|
|
||||||
SECURITY.md = SECURITY.md
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Core", "src\iOS.Core\iOS.Core.csproj", "{E71F3053-056C-4381-9638-048ED73BDFF6}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj", "{599E0201-420A-4C3E-A7BA-5349F72E0B15}"
|
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "test\Common\Common.csproj", "{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core.Test", "test\Core.Test\Core.Test.csproj", "{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\iOS.ShareExtension\iOS.ShareExtension.csproj", "{F8C3F648-EA5A-4719-8005-85D1690B1655}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.ShareExtension", "src\iOS.ShareExtension\iOS.ShareExtension.csproj", "{F8C3F648-EA5A-4719-8005-85D1690B1655}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{83449CC4-1F76-4CFE-92B1-D2E13A62506F}"
|
||||||
|
EndProject
|
||||||
|
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
|
||||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
|
||||||
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
|
||||||
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
|
||||||
AppStore|Any CPU = AppStore|Any CPU
|
|
||||||
AppStore|iPhone = AppStore|iPhone
|
|
||||||
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|iPhone = Debug|iPhone
|
|
||||||
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
|
||||||
FDroid|Any CPU = FDroid|Any CPU
|
|
||||||
FDroid|iPhone = FDroid|iPhone
|
|
||||||
FDroid|iPhoneSimulator = FDroid|iPhoneSimulator
|
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|iPhone = Release|iPhone
|
Debug|iPhoneSimulator = Debug|iPhoneSimulator
|
||||||
Release|iPhoneSimulator = Release|iPhoneSimulator
|
Release|iPhoneSimulator = Release|iPhoneSimulator
|
||||||
|
Debug|iPhone = Debug|iPhone
|
||||||
|
Release|iPhone = Release|iPhone
|
||||||
|
AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
|
||||||
|
AppStore|iPhone = AppStore|iPhone
|
||||||
|
Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
|
||||||
|
Ad-Hoc|iPhone = Ad-Hoc|iPhone
|
||||||
|
FDroid|Any CPU = FDroid|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Build.0 = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
{971FDF07-E288-4239-B47A-E9E7E912193B}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|Any CPU.Deploy.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhone.Deploy.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.FDroid|iPhoneSimulator.Deploy.0 = FDroid|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Build.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Build.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhone.Deploy.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.ActiveCfg = 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.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|Any CPU.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhone.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|Any CPU.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhone.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.AppStore|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhone.Deploy.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhone.Deploy.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.ActiveCfg = AppStore|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|Any CPU.Build.0 = AppStore|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|iPhone
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.ActiveCfg = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhone.Build.0 = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|iPhoneSimulator.Build.0 = FDroid|Any CPU
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Build.0 = Debug|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
{E71F3053-056C-4381-9638-048ED73BDFF6}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|Any CPU.ActiveCfg = FDroid|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.ActiveCfg = FDroid|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhone.Build.0 = FDroid|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.ActiveCfg = FDroid|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.FDroid|iPhoneSimulator.Build.0 = FDroid|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|Any CPU.ActiveCfg = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.ActiveCfg = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhone.Build.0 = Release|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|Any CPU.Build.0 = AppStore|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Build.0 = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|Any CPU.Build.0 = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhone.Build.0 = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|Any CPU.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.ActiveCfg = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|iPhone
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhone.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhone.Build.0 = Debug|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhone.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|Any CPU.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhone.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|Any CPU.Build.0 = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhone.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhone.Build.0 = Debug|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|Any CPU.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhone.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.FDroid|iPhoneSimulator.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhone.ActiveCfg = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.AppStore|iPhone.Build.0 = Release|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.FDroid|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44}.FDroid|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|iPhone
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.Build.0 = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.Build.0 = AppStore|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Deploy.0 = Debug|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.Build.0 = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.Build.0 = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|Any CPU.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.ActiveCfg = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.Build.0 = Release|iPhone
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
{304400AF-F0ED-40FA-B102-EA3C3EC43E4F} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{EE44C6A1-2A85-45FE-8D9B-BF1D5F88809C} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{4B8A8C41-9820-4341-974C-41E65B7F4366} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{9C8DA5A8-904D-466F-B9B0-1A4AB5A9AFC3} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
|
||||||
{2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
|
|
||||||
{256F9E44-0AF5-4D97-A2F9-DA26080C0A5D} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
|
|
||||||
{E71F3053-056C-4381-9638-048ED73BDFF6} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{599E0201-420A-4C3E-A7BA-5349F72E0B15} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
|
||||||
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
|
|
||||||
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}
|
SolutionGuid = {3B3A9B6C-D325-4BB3-97D3-8070630C5D3B}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(MonoDevelopProperties) = preSolution
|
||||||
|
Policies = $0
|
||||||
|
$0.DotNetNamingPolicy = $1
|
||||||
|
$1.DirectoryNamespaceAssociation = PrefixedHierarchical
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{971FDF07-E288-4239-B47A-E9E7E912193B} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
|
||||||
|
{11DBC05E-F8B4-49ED-AAC9-96D92336D21C} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
|
||||||
|
{83449CC4-1F76-4CFE-92B1-D2E13A62506F} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
|
||||||
|
{E71F3053-056C-4381-9638-048ED73BDFF6} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
|
||||||
|
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
|
||||||
|
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {B972BBFA-917F-4A10-B07E-B89CFEC6BBDC}
|
||||||
|
{137959BD-073B-4EC7-8ED5-31D73FA7DBC6} = {BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0}
|
||||||
|
{1AC5ED7F-301E-4B3C-ACDE-C0EADFA5AE44} = {BB702EBD-3B79-4ECA-A2A6-1237B07F0AF0}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
103
build.cake
103
build.cake
@@ -15,16 +15,18 @@ abstract record VariantConfig(
|
|||||||
string AppName,
|
string AppName,
|
||||||
string AndroidPackageName,
|
string AndroidPackageName,
|
||||||
string iOSBundleId,
|
string iOSBundleId,
|
||||||
string ApsEnvironment
|
string ApsEnvironment,
|
||||||
|
string DistProvisioningProfilePrefix
|
||||||
);
|
);
|
||||||
|
|
||||||
const string BASE_BUNDLE_ID_DROID = "com.x8bit.bitwarden";
|
const string BASE_BUNDLE_ID_DROID = "com.x8bit.bitwarden";
|
||||||
const string BASE_BUNDLE_ID_IOS = "com.8bit.bitwarden";
|
const string BASE_BUNDLE_ID_IOS = "com.8bit.bitwarden";
|
||||||
|
|
||||||
record Dev(): VariantConfig("Bitwarden Dev", $"{BASE_BUNDLE_ID_DROID}.dev", $"{BASE_BUNDLE_ID_IOS}.dev", "development");
|
//NOTE: Beta iOS variants have a different ITSEncryptionExportComplianceCode
|
||||||
record QA(): VariantConfig("Bitwarden QA", $"{BASE_BUNDLE_ID_DROID}.qa", $"{BASE_BUNDLE_ID_IOS}.qa", "development");
|
record Dev(): VariantConfig("Bitwarden Dev", $"{BASE_BUNDLE_ID_DROID}.dev", $"{BASE_BUNDLE_ID_IOS}.dev", "development", "Dist:");
|
||||||
record Beta(): VariantConfig("Bitwarden Beta", $"{BASE_BUNDLE_ID_DROID}.beta", $"{BASE_BUNDLE_ID_IOS}.beta", "production");
|
record QA(): VariantConfig("Bitwarden QA", $"{BASE_BUNDLE_ID_DROID}.qa", $"{BASE_BUNDLE_ID_IOS}.qa", "development", "Dist:");
|
||||||
record Prod(): VariantConfig("Bitwarden", $"{BASE_BUNDLE_ID_DROID}", $"{BASE_BUNDLE_ID_IOS}", "production");
|
record Beta(): VariantConfig("Bitwarden Beta", $"{BASE_BUNDLE_ID_DROID}.beta", $"{BASE_BUNDLE_ID_IOS}.beta", "production", "Dist: Beta");
|
||||||
|
record Prod(): VariantConfig("Bitwarden", $"{BASE_BUNDLE_ID_DROID}", $"{BASE_BUNDLE_ID_IOS}", "production", "Dist:");
|
||||||
|
|
||||||
VariantConfig GetVariant() => variant.ToLower() switch{
|
VariantConfig GetVariant() => variant.ToLower() switch{
|
||||||
"qa" => new QA(),
|
"qa" => new QA(),
|
||||||
@@ -67,7 +69,7 @@ Task("UpdateAndroidManifest")
|
|||||||
.Does(()=>
|
.Does(()=>
|
||||||
{
|
{
|
||||||
var buildVariant = GetVariant();
|
var buildVariant = GetVariant();
|
||||||
var manifestPath = Path.Combine(_slnPath, "src", "Android", "Properties", "AndroidManifest.xml");
|
var manifestPath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "AndroidManifest.xml");
|
||||||
|
|
||||||
// Cake.AndroidAppManifest doesn't currently enable us to access nested items so, quick (not ideal) fix:
|
// Cake.AndroidAppManifest doesn't currently enable us to access nested items so, quick (not ideal) fix:
|
||||||
var manifestText = FileReadText(manifestPath);
|
var manifestText = FileReadText(manifestPath);
|
||||||
@@ -119,26 +121,26 @@ Task("UpdateAndroidCodeFiles")
|
|||||||
//We're not using _androidPackageName here because the codefile is currently slightly different string than the one in AndroidManifest.xml
|
//We're not using _androidPackageName here because the codefile is currently slightly different string than the one in AndroidManifest.xml
|
||||||
var keyName = "com.8bit.bitwarden";
|
var keyName = "com.8bit.bitwarden";
|
||||||
var fixedPackageName = buildVariant.AndroidPackageName.Replace("x8bit", "8bit");
|
var fixedPackageName = buildVariant.AndroidPackageName.Replace("x8bit", "8bit");
|
||||||
var filePath = Path.Combine(_slnPath, "src", "Android", "Services", "BiometricService.cs");
|
var filePath = Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "BiometricService.cs");
|
||||||
ReplaceInFile(filePath, keyName, fixedPackageName);
|
ReplaceInFile(filePath, keyName, fixedPackageName);
|
||||||
|
|
||||||
var packageFileList = new string[] {
|
var packageFileList = new string[] {
|
||||||
Path.Combine(_slnPath, "src", "Android", "MainActivity.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainActivity.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "MainApplication.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "MainApplication.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Constants.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Constants.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Accessibility", "AccessibilityService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Accessibility", "AccessibilityService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillHelpers.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillHelpers.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "ClearClipboardAlarmReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "EventUploadReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "EventUploadReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "PackageReplacedReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "PackageReplacedReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Receivers", "RestrictionsChangedReceiver.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Services", "DeviceActionService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "DeviceActionService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Services", "FileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Services", "FileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Tiles", "AutofillTileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "AutofillTileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Tiles", "GeneratorTileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "GeneratorTileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "Tiles", "MyVaultTileService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Tiles", "MyVaultTileService.cs"),
|
||||||
Path.Combine(_slnPath, "src", "Android", "google-services.json"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "google-services.json"),
|
||||||
Path.Combine(_slnPath, "store", "google", "Publisher", "Program.cs"),
|
Path.Combine(_slnPath, "store", "google", "Publisher", "Program.cs"),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,7 +150,7 @@ Task("UpdateAndroidCodeFiles")
|
|||||||
}
|
}
|
||||||
|
|
||||||
var labelFileList = new string[] {
|
var labelFileList = new string[] {
|
||||||
Path.Combine(_slnPath, "src", "Android", "Autofill", "AutofillService.cs"),
|
Path.Combine(_slnPath, "src", "App", "Platforms", "Android", "Autofill", "AutofillService.cs"),
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach(string path in labelFileList)
|
foreach(string path in labelFileList)
|
||||||
@@ -197,7 +199,8 @@ private void UpdateiOSInfoPlist(string plistPath, VariantConfig buildVariant, Gi
|
|||||||
var prevBundleId = plist["CFBundleIdentifier"];
|
var prevBundleId = plist["CFBundleIdentifier"];
|
||||||
var prevBundleName = plist["CFBundleName"];
|
var prevBundleName = plist["CFBundleName"];
|
||||||
//var newVersion = CreateBuildNumber(prevVersion).ToString();
|
//var newVersion = CreateBuildNumber(prevVersion).ToString();
|
||||||
var newVersionName = GetVersionName(prevVersionName, buildVariant, git);
|
// we need to maintain version formatting here composed of one to three period-separated integers, so we cannot use the GetVersionName method as in Android for non-Prod.
|
||||||
|
var newVersionName = prevVersionName;
|
||||||
var newBundleId = GetiOSBundleId(buildVariant, projectType);
|
var newBundleId = GetiOSBundleId(buildVariant, projectType);
|
||||||
var newBundleName = GetiOSBundleName(buildVariant, projectType);
|
var newBundleName = GetiOSBundleName(buildVariant, projectType);
|
||||||
|
|
||||||
@@ -219,6 +222,11 @@ private void UpdateiOSInfoPlist(string plistPath, VariantConfig buildVariant, Gi
|
|||||||
plist["NSExtension"]["NSExtensionAttributes"]["NSExtensionActivationRule"] = keyText.Replace("com.8bit.bitwarden", buildVariant.iOSBundleId);
|
plist["NSExtension"]["NSExtensionAttributes"]["NSExtensionActivationRule"] = keyText.Replace("com.8bit.bitwarden", buildVariant.iOSBundleId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(buildVariant is Beta)
|
||||||
|
{
|
||||||
|
plist["ITSEncryptionExportComplianceCode"] = "3dd3e32f-efa6-4d99-b410-28aa28b1cb77";
|
||||||
|
}
|
||||||
|
|
||||||
SerializePlist(plistFile, plist);
|
SerializePlist(plistFile, plist);
|
||||||
|
|
||||||
Information($"Changed app name from {prevBundleName} to {newBundleName}");
|
Information($"Changed app name from {prevBundleName} to {newBundleName}");
|
||||||
@@ -228,12 +236,15 @@ private void UpdateiOSInfoPlist(string plistPath, VariantConfig buildVariant, Gi
|
|||||||
Information($"{plistPath} updated with success!");
|
Information($"{plistPath} updated with success!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateiOSEntitlementsPlist(string entitlementsPath, VariantConfig buildVariant)
|
private void UpdateiOSEntitlementsPlist(string entitlementsPath, VariantConfig buildVariant, bool updateApsEnv)
|
||||||
{
|
{
|
||||||
var EntitlementlistFile = File(entitlementsPath);
|
var EntitlementlistFile = File(entitlementsPath);
|
||||||
dynamic Entitlements = DeserializePlist(EntitlementlistFile);
|
dynamic Entitlements = DeserializePlist(EntitlementlistFile);
|
||||||
|
|
||||||
Entitlements["aps-environment"] = buildVariant.ApsEnvironment;
|
if (updateApsEnv)
|
||||||
|
{
|
||||||
|
Entitlements["aps-environment"] = buildVariant.ApsEnvironment;
|
||||||
|
}
|
||||||
Entitlements["keychain-access-groups"] = new List<string>() { "$(AppIdentifierPrefix)" + buildVariant.iOSBundleId };
|
Entitlements["keychain-access-groups"] = new List<string>() { "$(AppIdentifierPrefix)" + buildVariant.iOSBundleId };
|
||||||
Entitlements["com.apple.security.application-groups"] = new List<string>() { $"group.{buildVariant.iOSBundleId}" };;
|
Entitlements["com.apple.security.application-groups"] = new List<string>() { $"group.{buildVariant.iOSBundleId}" };;
|
||||||
|
|
||||||
@@ -272,9 +283,10 @@ private void UpdateWatchPbxproj(string pbxprojPath, string newVersion)
|
|||||||
const string pattern = @"MARKETING_VERSION = [^;]*;";
|
const string pattern = @"MARKETING_VERSION = [^;]*;";
|
||||||
|
|
||||||
fileText = Regex.Replace(fileText, pattern, $"MARKETING_VERSION = {newVersion};");
|
fileText = Regex.Replace(fileText, pattern, $"MARKETING_VERSION = {newVersion};");
|
||||||
|
|
||||||
FileWriteText(pbxprojPath, fileText);
|
FileWriteText(pbxprojPath, fileText);
|
||||||
Information($"{pbxprojPath} modified successfully.");
|
|
||||||
|
Information($"{pbxprojPath} modified Marketing Version successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -315,7 +327,7 @@ private void UpdateAppleIcons(string target, string appiconsetTarget)
|
|||||||
|
|
||||||
Task("UpdateiOSIcons")
|
Task("UpdateiOSIcons")
|
||||||
.Does(()=>{
|
.Does(()=>{
|
||||||
UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset"));
|
UpdateAppleIcons("ios", Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Resources", "Assets.xcassets", "AppIcons.appiconset"));
|
||||||
UpdateAppleIcons("watch", Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden WatchKit App", "Assets.xcassets", "AppIcon.appiconset"));
|
UpdateAppleIcons("watch", Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden WatchKit App", "Assets.xcassets", "AppIcon.appiconset"));
|
||||||
// TODO: Update complication icons when they start working
|
// TODO: Update complication icons when they start working
|
||||||
});
|
});
|
||||||
@@ -324,10 +336,10 @@ Task("UpdateiOSPlist")
|
|||||||
.IsDependentOn("GetGitInfo")
|
.IsDependentOn("GetGitInfo")
|
||||||
.Does(()=> {
|
.Does(()=> {
|
||||||
var buildVariant = GetVariant();
|
var buildVariant = GetVariant();
|
||||||
var infoPath = Path.Combine(_slnPath, "src", "iOS", "Info.plist");
|
var infoPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Info.plist");
|
||||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS", "Entitlements.plist");
|
var entitlementsPath = Path.Combine(_slnPath, "src", "App", "Platforms", "iOS", "Entitlements.plist");
|
||||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
|
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.MainApp);
|
||||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
Task("UpdateiOSAutofillPlist")
|
Task("UpdateiOSAutofillPlist")
|
||||||
@@ -338,7 +350,7 @@ Task("UpdateiOSAutofillPlist")
|
|||||||
var infoPath = Path.Combine(_slnPath, "src", "iOS.Autofill", "Info.plist");
|
var infoPath = Path.Combine(_slnPath, "src", "iOS.Autofill", "Info.plist");
|
||||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.Autofill", "Entitlements.plist");
|
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.Autofill", "Entitlements.plist");
|
||||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.Autofill);
|
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.Autofill);
|
||||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Task("UpdateiOSExtensionPlist")
|
Task("UpdateiOSExtensionPlist")
|
||||||
@@ -349,7 +361,7 @@ Task("UpdateiOSExtensionPlist")
|
|||||||
var infoPath = Path.Combine(_slnPath, "src", "iOS.Extension", "Info.plist");
|
var infoPath = Path.Combine(_slnPath, "src", "iOS.Extension", "Info.plist");
|
||||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.Extension", "Entitlements.plist");
|
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.Extension", "Entitlements.plist");
|
||||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.Extension);
|
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.Extension);
|
||||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Task("UpdateiOSShareExtensionPlist")
|
Task("UpdateiOSShareExtensionPlist")
|
||||||
@@ -360,7 +372,7 @@ Task("UpdateiOSShareExtensionPlist")
|
|||||||
var infoPath = Path.Combine(_slnPath, "src", "iOS.ShareExtension", "Info.plist");
|
var infoPath = Path.Combine(_slnPath, "src", "iOS.ShareExtension", "Info.plist");
|
||||||
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.ShareExtension", "Entitlements.plist");
|
var entitlementsPath = Path.Combine(_slnPath, "src", "iOS.ShareExtension", "Entitlements.plist");
|
||||||
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.ShareExtension);
|
UpdateiOSInfoPlist(infoPath, buildVariant, _gitVersion, iOSProjectType.ShareExtension);
|
||||||
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant);
|
UpdateiOSEntitlementsPlist(entitlementsPath, buildVariant, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
Task("UpdateiOSCodeFiles")
|
Task("UpdateiOSCodeFiles")
|
||||||
@@ -397,6 +409,22 @@ Task("UpdateWatchKitAppInfoPlist")
|
|||||||
UpdateWatchKitAppInfoPlist(infoPath, buildVariant);
|
UpdateWatchKitAppInfoPlist(infoPath, buildVariant);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Task("UpdateDistProfiles")
|
||||||
|
.IsDependentOn("UpdateiOSCodeFiles")
|
||||||
|
.Does(()=> {
|
||||||
|
var buildVariant = GetVariant();
|
||||||
|
|
||||||
|
var filesToReplace = new string[] {
|
||||||
|
Path.Combine(".github", "resources", "export-options-app-store.plist"),
|
||||||
|
Path.Combine(_slnPath, "src", "watchOS", "bitwarden", "bitwarden.xcodeproj", "project.pbxproj")
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach(string path in filesToReplace)
|
||||||
|
{
|
||||||
|
ReplaceInFile(path, "Dist:", buildVariant.DistProvisioningProfilePrefix);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
#endregion iOS
|
#endregion iOS
|
||||||
|
|
||||||
#region Main Tasks
|
#region Main Tasks
|
||||||
@@ -418,6 +446,7 @@ Task("iOS")
|
|||||||
.IsDependentOn("UpdateiOSCodeFiles")
|
.IsDependentOn("UpdateiOSCodeFiles")
|
||||||
.IsDependentOn("UpdateWatchProject")
|
.IsDependentOn("UpdateWatchProject")
|
||||||
.IsDependentOn("UpdateWatchKitAppInfoPlist")
|
.IsDependentOn("UpdateWatchKitAppInfoPlist")
|
||||||
|
.IsDependentOn("UpdateDistProfiles")
|
||||||
.Does(()=>
|
.Does(()=>
|
||||||
{
|
{
|
||||||
Information("iOS app updated");
|
Information("iOS app updated");
|
||||||
@@ -437,4 +466,4 @@ Options:
|
|||||||
});
|
});
|
||||||
#endregion Main Tasks
|
#endregion Main Tasks
|
||||||
|
|
||||||
RunTarget(target);
|
RunTarget(target);
|
||||||
|
|||||||
@@ -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/App/Resources/AppResources.resx
|
- source: /src/Core/Resources/Localization/AppResources.resx
|
||||||
dest: /src/App/Resources/%original_file_name%
|
dest: /src/Core/Resources/Localization/%original_file_name%
|
||||||
translation: /src/App/Resources/AppResources.%two_letters_code%.resx
|
translation: /src/Core/Resources/Localization/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:
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"sdk": {
|
|
||||||
"version": "7.0.400",
|
|
||||||
"rollForward": "latestPatch",
|
|
||||||
"allowPrerelease": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<doc>
|
||||||
|
<assembly>
|
||||||
|
<name>Xamarin.AndroidX.Credentials</name>
|
||||||
|
</assembly>
|
||||||
|
<members>
|
||||||
|
</members>
|
||||||
|
</doc>
|
||||||
Binary file not shown.
7
nuget.config
Normal file
7
nuget.config
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?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" />
|
||||||
|
<add key="Local AndroidX Credentials" value="lib/android/Xamarin.AndroidX.Credentials" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -1,327 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{304400AF-F0ED-40FA-B102-EA3C3EC43E4F}</ProjectGuid>
|
|
||||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
|
||||||
<TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<RootNamespace>Bit.Droid</RootNamespace>
|
|
||||||
<AssemblyName>BitwardenAndroid</AssemblyName>
|
|
||||||
<AndroidApplication>True</AndroidApplication>
|
|
||||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
|
||||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
|
||||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
|
||||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
|
||||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
|
||||||
<TargetFrameworkVersion>v13.0</TargetFrameworkVersion>
|
|
||||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
|
||||||
<NuGetPackageImportStamp>
|
|
||||||
</NuGetPackageImportStamp>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>3</WarningLevel>
|
|
||||||
<AndroidSupportedAbis />
|
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugSymbols>false</DebugSymbols>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release</OutputPath>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
|
||||||
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
|
|
||||||
<DebugSymbols>false</DebugSymbols>
|
|
||||||
<OutputPath>bin\FDroid\</OutputPath>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
|
||||||
<DefineConstants>FDROID</DefineConstants>
|
|
||||||
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
|
||||||
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
|
||||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
|
||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
|
||||||
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Mono.Android" />
|
|
||||||
<Reference Include="Mono.Android.Export" />
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="System.Net.Http" Condition="'$(Configuration)'=='FDroid'" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Plugin.CurrentActivity">
|
|
||||||
<Version>2.1.0.4</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Portable.BouncyCastle">
|
|
||||||
<Version>1.9.0</Version>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.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>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Android.Graphics.Drawables;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportEffect(typeof(FabShadowEffect), "FabShadowEffect")]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class FabShadowEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached ()
|
|
||||||
{
|
|
||||||
if (Control is Android.Widget.Button button)
|
|
||||||
{
|
|
||||||
var gd = new GradientDrawable();
|
|
||||||
gd.SetColor(ThemeHelpers.FabColor);
|
|
||||||
gd.SetCornerRadius(100);
|
|
||||||
|
|
||||||
button.SetBackground(gd);
|
|
||||||
button.Elevation = 6;
|
|
||||||
button.TranslationZ = 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportEffect(typeof(FixedSizeEffect), "FixedSizeEffect")]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class FixedSizeEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached()
|
|
||||||
{
|
|
||||||
if (Element is Label label && Control is TextView textView)
|
|
||||||
{
|
|
||||||
textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportEffect(typeof(RemoveFontPaddingEffect), nameof(RemoveFontPaddingEffect))]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class RemoveFontPaddingEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached()
|
|
||||||
{
|
|
||||||
if (Control is TextView textView)
|
|
||||||
{
|
|
||||||
textView.SetIncludeFontPadding(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Android.Views;
|
|
||||||
using Bit.Droid.Effects;
|
|
||||||
using Google.Android.Material.BottomNavigation;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ResolutionGroupName("Bitwarden")]
|
|
||||||
[assembly: ExportEffect(typeof(TabBarEffect), "TabBarEffect")]
|
|
||||||
namespace Bit.Droid.Effects
|
|
||||||
{
|
|
||||||
public class TabBarEffect : PlatformEffect
|
|
||||||
{
|
|
||||||
protected override void OnAttached()
|
|
||||||
{
|
|
||||||
if (!(Container.GetChildAt(0) is ViewGroup layout))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bottomNavigationView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityLabeled;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnDetached()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("BitwardenAndroid")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("Bitwarden Inc.")]
|
|
||||||
[assembly: AssemblyProduct("Bitwarden")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomEditorRenderer : EditorRenderer
|
|
||||||
{
|
|
||||||
public CustomEditorRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
// Workaround for issue described here:
|
|
||||||
// https://github.com/xamarin/Xamarin.Forms/issues/8291#issuecomment-617456651
|
|
||||||
protected override void OnAttachedToWindow()
|
|
||||||
{
|
|
||||||
base.OnAttachedToWindow();
|
|
||||||
EditText.Enabled = false;
|
|
||||||
EditText.Enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBorderColor();
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
|
||||||
Control.PaddingBottom + 20);
|
|
||||||
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
|
||||||
(ImeAction)ImeFlags.NoExtractUi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Entry.TextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBorderColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBorderColor()
|
|
||||||
{
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
var states = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
|
||||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
|
||||||
};
|
|
||||||
var colors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.PrimaryColor,
|
|
||||||
ThemeHelpers.MutedColor
|
|
||||||
};
|
|
||||||
Control.BackgroundTintList = new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Android.Graphics;
|
|
||||||
using Android.Text;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Android.Widget;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomEntryRenderer : EntryRenderer
|
|
||||||
{
|
|
||||||
public CustomEntryRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBorderColor();
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
|
||||||
Control.PaddingBottom + 20);
|
|
||||||
Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
|
||||||
(ImeAction)ImeFlags.NoExtractUi;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for bug preventing long-press -> copy/paste on Android 11
|
|
||||||
// See https://issuetracker.google.com/issues/37095917
|
|
||||||
protected override void OnAttachedToWindow()
|
|
||||||
{
|
|
||||||
base.OnAttachedToWindow();
|
|
||||||
Control.Enabled = false;
|
|
||||||
Control.Enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for failure to disable text prediction on non-password fields
|
|
||||||
// see https://github.com/xamarin/Xamarin.Forms/issues/10857
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
// Check if changed property is "IsPassword", otherwise ignore
|
|
||||||
if (e.PropertyName == Entry.IsPasswordProperty.PropertyName)
|
|
||||||
{
|
|
||||||
// Check if field type is text, otherwise ignore (numeric passwords, etc.)
|
|
||||||
EditText.InputType = Element.Keyboard.ToInputType();
|
|
||||||
bool isText = (EditText.InputType & InputTypes.ClassText) == InputTypes.ClassText,
|
|
||||||
isNumber = (EditText.InputType & InputTypes.ClassNumber) == InputTypes.ClassNumber;
|
|
||||||
if (isText || isNumber)
|
|
||||||
{
|
|
||||||
if (Element.IsPassword)
|
|
||||||
{
|
|
||||||
// Element is a password field, set inputType to TextVariationPassword which disables
|
|
||||||
// predictive text by default
|
|
||||||
EditText.InputType = EditText.InputType |
|
|
||||||
(isText ? InputTypes.TextVariationPassword : InputTypes.NumberVariationPassword);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Element is not a password field, set inputType to TextVariationVisiblePassword to
|
|
||||||
// disable predictive text while still displaying the content.
|
|
||||||
EditText.InputType = EditText.InputType |
|
|
||||||
(isText ? InputTypes.TextVariationVisiblePassword : InputTypes.NumberVariationNormal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The workaround above forces a reset of the style properties, so we need to re-apply the font.
|
|
||||||
// see https://xamarin.github.io/bugzilla-archives/33/33666/bug.html
|
|
||||||
var typeface = Typeface.CreateFromAsset(Context.Assets, "RobotoMono_Regular.ttf");
|
|
||||||
if (Control is TextView label)
|
|
||||||
{
|
|
||||||
label.Typeface = typeface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBorderColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBorderColor()
|
|
||||||
{
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
var states = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
|
||||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
|
||||||
};
|
|
||||||
var colors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.PrimaryColor,
|
|
||||||
ThemeHelpers.MutedColor
|
|
||||||
};
|
|
||||||
Control.BackgroundTintList = new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Android.App;
|
|
||||||
using Android.Content;
|
|
||||||
using AndroidX.AppCompat.Widget;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomPageRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomPageRenderer : PageRenderer
|
|
||||||
{
|
|
||||||
public CustomPageRenderer(Context context) : base(context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
|
|
||||||
Activity context = (Activity)this.Context;
|
|
||||||
var toolbar = context.FindViewById<Toolbar>(Resource.Id.toolbar);
|
|
||||||
if(toolbar != null)
|
|
||||||
{
|
|
||||||
toolbar.NavigationContentDescription = AppResources.TapToGoBack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomPickerRenderer : PickerRenderer
|
|
||||||
{
|
|
||||||
public CustomPickerRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBorderColor();
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
|
||||||
Control.PaddingBottom + 20);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Picker.TextColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBorderColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBorderColor()
|
|
||||||
{
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
var states = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
|
||||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
|
||||||
};
|
|
||||||
var colors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.PrimaryColor,
|
|
||||||
ThemeHelpers.MutedColor
|
|
||||||
};
|
|
||||||
Control.BackgroundTintList = new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Views.InputMethods;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomSearchBarRenderer : SearchBarRenderer
|
|
||||||
{
|
|
||||||
public CustomSearchBarRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (Control != null && e.NewElement != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var magId = Resources.GetIdentifier("android:id/search_mag_icon", null, null);
|
|
||||||
var magImage = (Android.Widget.ImageView)Control.FindViewById(magId);
|
|
||||||
magImage.LayoutParameters = new Android.Widget.LinearLayout.LayoutParams(0, 0);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
Control.SetImeOptions(Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
|
||||||
(ImeAction)ImeFlags.NoExtractUi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Content.Res;
|
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using Android.OS;
|
|
||||||
using AndroidX.Core.Content.Resources;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Bit.Droid.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(Switch), typeof(CustomSwitchRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomSwitchRenderer : SwitchRenderer
|
|
||||||
{
|
|
||||||
public CustomSwitchRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateColors();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == Switch.OnColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateColors();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateColors()
|
|
||||||
{
|
|
||||||
if (Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
|
|
||||||
{
|
|
||||||
// Android 5.x doesn't support ThumbTintList, and using SwitchCompat on every version after 5.x
|
|
||||||
// doesn't apply tinting the way we want. Let 5.x to do its own thing here.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
Control.SetHintTextColor(ThemeHelpers.MutedColor);
|
|
||||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.switch_thumb, null);
|
|
||||||
if (t is GradientDrawable thumb)
|
|
||||||
{
|
|
||||||
Control.ThumbDrawable = thumb;
|
|
||||||
}
|
|
||||||
var thumbStates = new[]
|
|
||||||
{
|
|
||||||
new[] { Android.Resource.Attribute.StateChecked }, // checked
|
|
||||||
new[] { -Android.Resource.Attribute.StateChecked }, // unchecked
|
|
||||||
};
|
|
||||||
var thumbColors = new int[]
|
|
||||||
{
|
|
||||||
ThemeHelpers.SwitchOnColor,
|
|
||||||
ThemeHelpers.SwitchThumbColor
|
|
||||||
};
|
|
||||||
Control.ThumbTintList = new ColorStateList(thumbStates, thumbColors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Pages;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Google.Android.Material.BottomNavigation;
|
|
||||||
using Google.Android.Material.Navigation;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
using Xamarin.Forms.Platform.Android.AppCompat;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class CustomTabbedRenderer : TabbedPageRenderer, NavigationBarView.IOnItemReselectedListener
|
|
||||||
{
|
|
||||||
private TabbedPage _page;
|
|
||||||
|
|
||||||
public CustomTabbedRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (e.NewElement != null)
|
|
||||||
{
|
|
||||||
_page = e.NewElement;
|
|
||||||
GetBottomNavigationView()?.SetOnItemReselectedListener(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_page = e.OldElement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BottomNavigationView GetBottomNavigationView()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < ViewGroup.ChildCount; i++)
|
|
||||||
{
|
|
||||||
var childView = ViewGroup.GetChildAt(i);
|
|
||||||
if (childView is ViewGroup viewGroup)
|
|
||||||
{
|
|
||||||
for (var j = 0; j < viewGroup.ChildCount; j++)
|
|
||||||
{
|
|
||||||
var childRelativeLayoutView = viewGroup.GetChildAt(j);
|
|
||||||
if (childRelativeLayoutView is BottomNavigationView bottomNavigationView)
|
|
||||||
{
|
|
||||||
return bottomNavigationView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnNavigationItemReselected(IMenuItem item)
|
|
||||||
{
|
|
||||||
if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
|
|
||||||
{
|
|
||||||
if (_page is TabsPage tabsPage)
|
|
||||||
{
|
|
||||||
tabsPage.OnPageReselected();
|
|
||||||
}
|
|
||||||
Device.BeginInvokeOnMainThread(async () => await _page.CurrentPage.Navigation.PopToRootAsync());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedDatePickerRenderer : DatePickerRenderer
|
|
||||||
{
|
|
||||||
public ExtendedDatePickerRenderer(Context context)
|
|
||||||
: base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (Control != null && Element is ExtendedDatePicker element)
|
|
||||||
{
|
|
||||||
// center text
|
|
||||||
Control.Gravity = GravityFlags.CenterHorizontal;
|
|
||||||
|
|
||||||
// use placeholder until NullableDate set
|
|
||||||
if (!element.NullableDate.HasValue)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == DatePicker.DateProperty.PropertyName ||
|
|
||||||
e.PropertyName == DatePicker.FormatProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedDatePicker element)
|
|
||||||
{
|
|
||||||
if (Element.Format == element.PlaceHolder)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedGrid), typeof(ExtendedGridRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedGridRenderer : ViewRenderer
|
|
||||||
{
|
|
||||||
public ExtendedGridRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(elementChangedEvent);
|
|
||||||
if (elementChangedEvent.NewElement != null)
|
|
||||||
{
|
|
||||||
SetBackgroundResource(Resource.Drawable.list_item_bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Graphics.Drawables;
|
|
||||||
using AndroidX.Core.Content.Resources;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedSlider), typeof(ExtendedSliderRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedSliderRenderer : SliderRenderer
|
|
||||||
{
|
|
||||||
public ExtendedSliderRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == ExtendedSlider.ThumbBorderColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateColor()
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedSlider view)
|
|
||||||
{
|
|
||||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
|
|
||||||
if (t is GradientDrawable thumb)
|
|
||||||
{
|
|
||||||
if (view.ThumbColor == Color.Default)
|
|
||||||
{
|
|
||||||
thumb.SetColor(Color.White.ToAndroid());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
thumb.SetColor(view.ThumbColor.ToAndroid());
|
|
||||||
}
|
|
||||||
thumb.SetStroke(3, view.ThumbBorderColor.ToAndroid());
|
|
||||||
Control.SetThumb(thumb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Android.Content;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedStackLayout), typeof(ExtendedStackLayoutRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedStackLayoutRenderer : ViewRenderer
|
|
||||||
{
|
|
||||||
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(elementChangedEvent);
|
|
||||||
if (elementChangedEvent.NewElement != null)
|
|
||||||
{
|
|
||||||
SetBackgroundResource(Resource.Drawable.list_item_bg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Graphics;
|
|
||||||
using Android.OS;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedStepper), typeof(ExtendedStepperRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedStepperRenderer : StepperRenderer
|
|
||||||
{
|
|
||||||
public ExtendedStepperRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
UpdateBgColor();
|
|
||||||
UpdateFgColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
|
|
||||||
if (e.PropertyName == ExtendedStepper.StepperBackgroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBgColor();
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == ExtendedStepper.StepperForegroundColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateFgColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateBgColor()
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedStepper view)
|
|
||||||
{
|
|
||||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
|
|
||||||
{
|
|
||||||
Control.GetChildAt(0)?.Background?.SetColorFilter(
|
|
||||||
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
|
|
||||||
Control.GetChildAt(1)?.Background?.SetColorFilter(
|
|
||||||
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), BlendMode.Multiply));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Control.GetChildAt(0)?.Background?.SetColorFilter(
|
|
||||||
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
|
|
||||||
Control.GetChildAt(1)?.Background?.SetColorFilter(
|
|
||||||
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateFgColor()
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedStepper view)
|
|
||||||
{
|
|
||||||
var btn0 = Control.GetChildAt(0) as Android.Widget.Button;
|
|
||||||
btn0?.SetTextColor(view.StepperForegroundColor.ToAndroid());
|
|
||||||
var btn1 = Control.GetChildAt(1) as Android.Widget.Button;
|
|
||||||
btn1?.SetTextColor(view.StepperForegroundColor.ToAndroid());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Android.Content;
|
|
||||||
using Android.Views;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(ExtendedTimePicker), typeof(ExtendedTimePickerRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class ExtendedTimePickerRenderer : TimePickerRenderer
|
|
||||||
{
|
|
||||||
public ExtendedTimePickerRenderer(Context context)
|
|
||||||
: base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
if (Control != null && Element is ExtendedTimePicker element)
|
|
||||||
{
|
|
||||||
// center text
|
|
||||||
Control.Gravity = GravityFlags.CenterHorizontal;
|
|
||||||
|
|
||||||
// use placeholder until NullableTime set
|
|
||||||
if (!element.NullableTime.HasValue)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName == TimePicker.TimeProperty.PropertyName ||
|
|
||||||
e.PropertyName == TimePicker.FormatProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Control != null && Element is ExtendedTimePicker element)
|
|
||||||
{
|
|
||||||
if (Element.Format == element.PlaceHolder)
|
|
||||||
{
|
|
||||||
Control.Text = element.PlaceHolder;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
using Android.Webkit;
|
|
||||||
using AWebkit = Android.Webkit;
|
|
||||||
using Java.Interop;
|
|
||||||
using Android.Content;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, AWebkit.WebView>
|
|
||||||
{
|
|
||||||
private const string JSFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
|
|
||||||
|
|
||||||
private readonly Context _context;
|
|
||||||
|
|
||||||
public HybridWebViewRenderer(Context context)
|
|
||||||
: base(context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
|
|
||||||
if (Control == null)
|
|
||||||
{
|
|
||||||
var webView = new AWebkit.WebView(_context);
|
|
||||||
webView.Settings.JavaScriptEnabled = true;
|
|
||||||
webView.SetWebViewClient(new JSWebViewClient(string.Format("javascript: {0}", JSFunction)));
|
|
||||||
SetNativeControl(webView);
|
|
||||||
}
|
|
||||||
if (e.OldElement != null)
|
|
||||||
{
|
|
||||||
Control.RemoveJavascriptInterface("jsBridge");
|
|
||||||
var hybridWebView = e.OldElement as HybridWebView;
|
|
||||||
hybridWebView.Cleanup();
|
|
||||||
}
|
|
||||||
if (e.NewElement != null)
|
|
||||||
{
|
|
||||||
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
|
|
||||||
Control.LoadUrl(Element.Uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnElementPropertyChanged(sender, e);
|
|
||||||
if (e.PropertyName == HybridWebView.UriProperty.PropertyName)
|
|
||||||
{
|
|
||||||
Control.LoadUrl(Element.Uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class JSBridge : Java.Lang.Object
|
|
||||||
{
|
|
||||||
private readonly WeakReference<HybridWebViewRenderer> _hybridWebViewRenderer;
|
|
||||||
|
|
||||||
public JSBridge(HybridWebViewRenderer hybridRenderer)
|
|
||||||
{
|
|
||||||
_hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
[JavascriptInterface]
|
|
||||||
[Export("invokeAction")]
|
|
||||||
public void InvokeAction(string data)
|
|
||||||
{
|
|
||||||
if (_hybridWebViewRenderer != null &&
|
|
||||||
_hybridWebViewRenderer.TryGetTarget(out HybridWebViewRenderer hybridRenderer))
|
|
||||||
{
|
|
||||||
hybridRenderer.Element.InvokeAction(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class JSWebViewClient : WebViewClient
|
|
||||||
{
|
|
||||||
private readonly string _javascript;
|
|
||||||
|
|
||||||
public JSWebViewClient(string javascript)
|
|
||||||
{
|
|
||||||
_javascript = javascript;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPageFinished(AWebkit.WebView view, string url)
|
|
||||||
{
|
|
||||||
base.OnPageFinished(view, url);
|
|
||||||
view.EvaluateJavascript(_javascript, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Android.Content;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.Droid.Renderers;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Platform.Android;
|
|
||||||
|
|
||||||
[assembly: ExportRenderer(typeof(SelectableLabel), typeof(SelectableLabelRenderer))]
|
|
||||||
namespace Bit.Droid.Renderers
|
|
||||||
{
|
|
||||||
public class SelectableLabelRenderer : LabelRenderer
|
|
||||||
{
|
|
||||||
public SelectableLabelRenderer(Context context) : base(context) { }
|
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
|
||||||
{
|
|
||||||
base.OnElementChanged(e);
|
|
||||||
|
|
||||||
if (Control != null)
|
|
||||||
{
|
|
||||||
Control.SetTextIsSelectable(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,441 +1,271 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFrameworks>net8.0-android;net8.0-ios</TargetFrameworks>
|
||||||
<RootNamespace>Bit.App</RootNamespace>
|
|
||||||
<AssemblyName>BitwardenApp</AssemblyName>
|
<!-- Uncomment to also build for Windows platform.-->
|
||||||
<Configurations>Debug;Release;FDroid</Configurations>
|
<!--<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>-->
|
||||||
|
|
||||||
|
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
|
||||||
|
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
|
||||||
|
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Bit.App</RootNamespace>
|
||||||
|
<UseMaui>true</UseMaui>
|
||||||
|
<SingleProject>true</SingleProject>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|
||||||
|
<!-- Display name -->
|
||||||
|
<ApplicationTitle>Bitwarden</ApplicationTitle>
|
||||||
|
|
||||||
|
<!-- App Identifier -->
|
||||||
|
<ApplicationId Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">com.8bit.bitwarden</ApplicationId>
|
||||||
|
<ApplicationId Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">com.x8bit.bitwarden</ApplicationId>
|
||||||
|
<ApplicationIdGuid>ccf4766c-a36c-4647-900c-0ea7d323ccc6</ApplicationIdGuid>
|
||||||
|
|
||||||
|
<!-- Versions -->
|
||||||
|
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
|
||||||
|
<ApplicationVersion>1</ApplicationVersion>
|
||||||
|
|
||||||
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
|
||||||
|
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||||
|
|
||||||
|
<ForceSimulatorX64ArchitectureInIDE>true</ForceSimulatorX64ArchitectureInIDE>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<DefineConstants Condition=" '$(CustomConstants)' != '' ">$(DefineConstants);$(CustomConstants)</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-android|AnyCPU'">
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<AndroidEnableMultiDex>True</AndroidEnableMultiDex>
|
||||||
<DebugType>pdbonly</DebugType>
|
<UseInterpreter>False</UseInterpreter>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>True</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-android|AnyCPU'">
|
||||||
<ItemGroup>
|
<AndroidEnableMultiDex>True</AndroidEnableMultiDex>
|
||||||
<PackageReference Include="Plugin.Fingerprint" Version="2.1.5" />
|
<UseInterpreter>False</UseInterpreter>
|
||||||
<PackageReference Include="SkiaSharp.Views.Forms" Version="2.88.3" />
|
<DebugSymbols>False</DebugSymbols>
|
||||||
<PackageReference Include="Xamarin.CommunityToolkit" Version="2.0.6" />
|
<RunAOTCompilation>False</RunAOTCompilation>
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.8.0" />
|
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
|
||||||
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
|
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
|
||||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2612" />
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
|
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
|
||||||
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
|
</PropertyGroup>
|
||||||
<PackageReference Include="MessagePack" Version="2.4.59" />
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-ios|AnyCPU'">
|
||||||
</ItemGroup>
|
<CreatePackage>false</CreatePackage>
|
||||||
|
<CodesignProvision>Automatic</CodesignProvision>
|
||||||
<ItemGroup>
|
<CodesignKey>iPhone Developer</CodesignKey>
|
||||||
<ProjectReference Include="..\Core\Core.csproj" />
|
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
|
||||||
</ItemGroup>
|
<UseInterpreter>true</UseInterpreter>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(RuntimeIdentifier)'=='Debug|net8.0-ios|iossimulator-x64'">
|
||||||
<Compile Update="Pages\Accounts\EnvironmentPage.xaml.cs">
|
<MtouchExtraArgs>$(Argon2IdLoadMtouchExtraArgs)</MtouchExtraArgs>
|
||||||
<DependentUpon>EnvironmentPage.xaml</DependentUpon>
|
</PropertyGroup>
|
||||||
</Compile>
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(RuntimeIdentifier)'=='Debug|net8.0-ios|ios-arm64'">
|
||||||
<Compile Update="Pages\Accounts\HintPage.xaml.cs">
|
<MtouchExtraArgs>$(Argon2IdLoadMtouchExtraArgs)</MtouchExtraArgs>
|
||||||
<DependentUpon>HintPage.xaml</DependentUpon>
|
</PropertyGroup>
|
||||||
</Compile>
|
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-ios|AnyCPU'">
|
||||||
<Compile Update="Pages\Accounts\LockPage.xaml.cs">
|
<CreatePackage>false</CreatePackage>
|
||||||
<DependentUpon>LockPage.xaml</DependentUpon>
|
<CodesignProvision>$(ReleaseCodesignProvision)</CodesignProvision>
|
||||||
</Compile>
|
<CodesignKey>$(ReleaseCodesignKey)</CodesignKey>
|
||||||
<Compile Update="Pages\Accounts\TwoFactorPage.xaml.cs">
|
<CodesignEntitlements>Platforms\iOS\Entitlements.plist</CodesignEntitlements>
|
||||||
<DependentUpon>TwoFactorPage.xaml</DependentUpon>
|
<UseInterpreter>true</UseInterpreter>
|
||||||
</Compile>
|
<MtouchExtraArgs>$(Argon2IdLoadMtouchExtraArgs)</MtouchExtraArgs>
|
||||||
<Compile Update="Pages\Accounts\RegisterPage.xaml.cs">
|
</PropertyGroup>
|
||||||
<DependentUpon>RegisterPage.xaml</DependentUpon>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
|
||||||
</Compile>
|
<!--This is needed for PCLCrypto to work correctly-->
|
||||||
<Compile Update="Pages\Accounts\LoginPage.xaml.cs">
|
<TrimmerRootAssembly Include="System.Security.Cryptography" />
|
||||||
<DependentUpon>LoginPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup>
|
||||||
<Compile Update="Pages\Generator\GeneratorPage.xaml.cs">
|
<AndroidNativeLibrary Include="Platforms\Android\lib\arm64-v8a\libargon2.so" />
|
||||||
<DependentUpon>GeneratorPage.xaml</DependentUpon>
|
<AndroidNativeLibrary Include="Platforms\Android\lib\armeabi-v7a\libargon2.so" />
|
||||||
</Compile>
|
<AndroidNativeLibrary Include="Platforms\Android\lib\x86\libargon2.so" />
|
||||||
<Compile Update="Pages\Generator\GeneratorHistoryPage.xaml.cs">
|
<AndroidNativeLibrary Include="Platforms\Android\lib\x86_64\libargon2.so" />
|
||||||
<DependentUpon>GeneratorHistoryPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup>
|
||||||
<Compile Update="Pages\Settings\AutofillPage.xaml.cs">
|
<PackageReference Include="Camera.MAUI" Version="1.4.4" />
|
||||||
<DependentUpon>AutofillPage.xaml</DependentUpon>
|
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||||
</Compile>
|
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||||
<Compile Update="Pages\Settings\ExtensionPage.xaml.cs">
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||||
<DependentUpon>ExtensionPage.xaml</DependentUpon>
|
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||||
</Compile>
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
<Compile Update="Pages\Settings\FolderAddEditPage.xaml.cs">
|
<PackageReference Include="MessagePack" Version="2.5.124" />
|
||||||
<DependentUpon>FolderAddEditPage.xaml</DependentUpon>
|
<PackageReference Include="MessagePack.MSBuild.Tasks" Version="2.5.124">
|
||||||
</Compile>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<Compile Update="Pages\Settings\FoldersPage.xaml.cs">
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<DependentUpon>FoldersPage.xaml</DependentUpon>
|
</PackageReference>
|
||||||
</Compile>
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<Compile Update="Pages\Settings\ExportVaultPage.xaml.cs">
|
<PackageReference Include="zxcvbn-core" Version="7.0.92" />
|
||||||
<DependentUpon>ExportVaultPage.xaml</DependentUpon>
|
<PackageReference Include="CommunityToolkit.Maui" Version="5.2.0" />
|
||||||
</Compile>
|
<PackageReference Include="Plugin.Fingerprint" Version="3.0.0-beta.1" />
|
||||||
<Compile Update="Pages\Vault\AttachmentsPage.xaml.cs">
|
<PackageReference Include="SkiaSharp.Views.Maui.Controls" Version="2.88.4-preview.84" />
|
||||||
<DependentUpon>AttachmentsPage.xaml</DependentUpon>
|
<PackageReference Include="SkiaSharp.Views.Maui.Controls.Compatibility" Version="2.88.4-preview.84" />
|
||||||
</Compile>
|
<PackageReference Include="FFImageLoadingCompat.Maui" Version="0.1.1" />
|
||||||
<Compile Update="Pages\Vault\AutofillCiphersPage.xaml.cs">
|
<PackageReference Include="AsyncAwaitBestPractices.MVVM" Version="6.0.6" />
|
||||||
<DependentUpon>AutofillCiphersPage.xaml</DependentUpon>
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
|
||||||
</Compile>
|
<PackageReference Include="PCLCrypto" Version="2.1.40-alpha" />
|
||||||
<Compile Update="Pages\Vault\CollectionsPage.xaml.cs">
|
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
|
||||||
<DependentUpon>CollectionsPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup>
|
||||||
<Compile Update="Pages\Vault\ScanPage.xaml.cs">
|
<Folder Include="Effects\" />
|
||||||
<DependentUpon>ScanPage.xaml</DependentUpon>
|
<Folder Include="Resources\" />
|
||||||
</Compile>
|
<Folder Include="Resources\AppIcon\" />
|
||||||
<Compile Update="Pages\Vault\SharePage.xaml.cs">
|
<Folder Include="Resources\Splash\" />
|
||||||
<DependentUpon>SharePage.xaml</DependentUpon>
|
<Folder Include="Platforms\Android\Accessibility\" />
|
||||||
</Compile>
|
<Folder Include="Platforms\Android\Autofill\" />
|
||||||
<Compile Update="Pages\Vault\CiphersPage.xaml.cs">
|
<Folder Include="Platforms\Android\Push\" />
|
||||||
<DependentUpon>CiphersPage.xaml</DependentUpon>
|
<Folder Include="Platforms\Android\Receivers\" />
|
||||||
</Compile>
|
<Folder Include="Platforms\Android\Services\" />
|
||||||
<Compile Update="Pages\Vault\PasswordHistoryPage.xaml.cs">
|
<Folder Include="Platforms\Android\Tiles\" />
|
||||||
<DependentUpon>PasswordHistoryPage.xaml</DependentUpon>
|
<Folder Include="Platforms\Android\Utilities\" />
|
||||||
</Compile>
|
<Folder Include="Platforms\Android\Resources\drawable-xxxhdpi\" />
|
||||||
<Compile Update="Pages\Vault\CipherDetailsPage.xaml.cs">
|
<Folder Include="Resources\Raw\" />
|
||||||
<DependentUpon>CipherDetailsPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||||
<Compile Update="Pages\Vault\CipherAddEditPage.xaml.cs">
|
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.18" />
|
||||||
<DependentUpon>CipherAddEditPage.xaml</DependentUpon>
|
<PackageReference Include="Xamarin.AndroidX.Activity.Ktx" Version="1.7.2.1" />
|
||||||
</Compile>
|
<PackageReference Include="Xamarin.AndroidX.Credentials" Version="1.0.0" />
|
||||||
<Compile Update="Pages\Settings\SettingsPage\SettingsPage.xaml.cs">
|
</ItemGroup>
|
||||||
<DependentUpon>SettingsPage.xaml</DependentUpon>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android' AND !$(DefineConstants.Contains(FDROID))">
|
||||||
</Compile>
|
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet" Version="118.0.1.5" />
|
||||||
<Compile Update="Pages\Vault\GroupingsPage\GroupingsPage.xaml.cs">
|
<PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.2.2" />
|
||||||
<DependentUpon>GroupingsPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="!$(DefineConstants.Contains(FDROID))">
|
||||||
<Compile Update="Pages\Accounts\LoginSsoPage.xaml.cs">
|
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="5.0.3" />
|
||||||
<DependentUpon>LoginSsoPage.xaml</DependentUpon>
|
</ItemGroup>
|
||||||
<SubType>Code</SubType>
|
<ItemGroup>
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher.png" />
|
||||||
<Compile Update="Pages\Accounts\SetPasswordPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||||
<DependentUpon>ResetMasterPasswordPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||||
<SubType>Code</SubType>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||||
<Compile Update="Pages\Send\SendGroupingsPage\SendGroupingsPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||||
<DependentUpon>SendGroupingsPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher.png" />
|
||||||
<SubType>Code</SubType>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher.png" />
|
||||||
<Compile Remove="Pages\Accounts\AccountsPopupPage.xaml.cs" />
|
<BundleResource Include="Platforms\Android\Resources\mipmap-mdpi\ic_launcher_round.png" />
|
||||||
<Compile Update="Pages\Accounts\LoginPasswordlessPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher.png" />
|
||||||
<DependentUpon>LoginPasswordlessPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-hdpi\ic_launcher_round.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher.png" />
|
||||||
<Compile Update="Pages\Accounts\LoginPasswordlessRequestPage.xaml.cs">
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxxhdpi\ic_launcher_round.png" />
|
||||||
<DependentUpon>LoginPasswordlessRequestPage.xaml</DependentUpon>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher.png" />
|
||||||
</Compile>
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xxhdpi\ic_launcher_round.png" />
|
||||||
</ItemGroup>
|
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\logo_legacy.png" />
|
||||||
|
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\yubikey.png" />
|
||||||
<ItemGroup>
|
<BundleResource Include="Platforms\Android\Resources\drawable-xhdpi\logo_white_legacy.png" />
|
||||||
<Folder Include="Resources\" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\logo_legacy.png" />
|
||||||
<Folder Include="Behaviors\" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\yubikey.png" />
|
||||||
<Folder Include="Lists\" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-xxhdpi\logo_white_legacy.png" />
|
||||||
<Folder Include="Lists\ItemLayouts\" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\logo_legacy.png" />
|
||||||
<Folder Include="Lists\DataTemplateSelectors\" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\yubikey.png" />
|
||||||
<Folder Include="Lists\ItemLayouts\CustomFields\" />
|
<BundleResource Include="Platforms\Android\Resources\drawable-hdpi\logo_white_legacy.png" />
|
||||||
<Folder Include="Lists\ItemViewModels\" />
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher.png" />
|
||||||
<Folder Include="Lists\ItemViewModels\CustomFields\" />
|
<BundleResource Include="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
||||||
<Folder Include="Controls\AccountSwitchingOverlay\" />
|
<BundleResource Include="Platforms\iOS\Resources\logo.png" />
|
||||||
<Folder Include="Utilities\AccountManagement\" />
|
<BundleResource Include="Platforms\iOS\Resources\logo_white%402x.png" />
|
||||||
<Folder Include="Controls\DateTime\" />
|
<BundleResource Include="Platforms\iOS\Resources\more_vert%402x.png" />
|
||||||
<Folder Include="Controls\IconLabelButton\" />
|
<BundleResource Include="Platforms\iOS\Resources\logo_white%403x.png" />
|
||||||
<Folder Include="Controls\PasswordStrengthProgressBar\" />
|
<BundleResource Include="Platforms\iOS\Resources\logo%403x.png" />
|
||||||
<Folder Include="Utilities\Automation\" />
|
<BundleResource Include="Platforms\iOS\Resources\more_vert%403x.png" />
|
||||||
<Folder Include="Utilities\Prompts\" />
|
<BundleResource Include="Platforms\iOS\Resources\more_vert.png" />
|
||||||
<Folder Include="Controls\Settings\" />
|
<BundleResource Include="Platforms\iOS\Resources\logo_white.png" />
|
||||||
</ItemGroup>
|
<BundleResource Include="Platforms\iOS\Resources\logo%402x.png" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Remove="Pages\Accounts\AccountsPopupPage.xaml" />
|
<ProjectReference Include="..\iOS.Core\iOS.Core.csproj" Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'" />
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\Core\Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="Styles\Black.xaml.cs">
|
<!-- App Icon -->
|
||||||
<DependentUpon>Black.xaml</DependentUpon>
|
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
|
||||||
</Compile>
|
</ItemGroup>
|
||||||
<Compile Update="Styles\Nord.xaml.cs">
|
<ItemGroup>
|
||||||
<DependentUpon>Nord.xaml</DependentUpon>
|
<MauiImage Include="Resources\cog_settings.svg">
|
||||||
</Compile>
|
<BaseSize>24,24</BaseSize>
|
||||||
<Compile Update="Styles\Variables.xaml.cs">
|
</MauiImage>
|
||||||
<DependentUpon>Variables.xaml</DependentUpon>
|
<MauiImage Include="Resources\ext_act.png" />
|
||||||
</Compile>
|
<MauiImage Include="Resources\ext_more.png" />
|
||||||
<Compile Update="Styles\Light.xaml.cs">
|
<MauiImage Include="Resources\ext_use.png" />
|
||||||
<DependentUpon>Light.xaml</DependentUpon>
|
<MauiImage Include="Resources\generate.svg">
|
||||||
</Compile>
|
<BaseSize>24,24</BaseSize>
|
||||||
<Compile Update="Styles\Dark.xaml.cs">
|
</MauiImage>
|
||||||
<DependentUpon>Dark.xaml</DependentUpon>
|
<MauiImage Include="Resources\info.svg">
|
||||||
</Compile>
|
<BaseSize>24,24</BaseSize>
|
||||||
<Compile Update="Styles\iOS.xaml.cs">
|
</MauiImage>
|
||||||
<DependentUpon>iOS.xaml</DependentUpon>
|
<MauiImage Include="Resources\lock.svg">
|
||||||
</Compile>
|
<BaseSize>24,24</BaseSize>
|
||||||
<Compile Update="Styles\Android.xaml.cs">
|
</MauiImage>
|
||||||
<DependentUpon>Android.xaml</DependentUpon>
|
<MauiImage Include="Resources\login.svg">
|
||||||
</Compile>
|
<BaseSize>24,24</BaseSize>
|
||||||
</ItemGroup>
|
</MauiImage>
|
||||||
|
<MauiImage Include="Resources\logo_white.png" />
|
||||||
<ItemGroup>
|
<MauiImage Include="Resources\logo.png" />
|
||||||
<Compile Update="Resources\AppResources.cs.Designer.cs">
|
<MauiImage Include="Resources\more_vert.svg">
|
||||||
<DependentUpon>AppResources.cs.resx</DependentUpon>
|
<BaseSize>24,24</BaseSize>
|
||||||
<DesignTime>True</DesignTime>
|
</MauiImage>
|
||||||
<AutoGen>True</AutoGen>
|
<MauiImage Include="Resources\more.svg">
|
||||||
</Compile>
|
<BaseSize>24,24</BaseSize>
|
||||||
<Compile Update="Resources\AppResources.da.Designer.cs">
|
</MauiImage>
|
||||||
<DependentUpon>AppResources.da.resx</DependentUpon>
|
<MauiImage Include="Resources\plus.svg" TintColor="#FFFFFFFF">
|
||||||
<DesignTime>True</DesignTime>
|
<BaseSize>24,24</BaseSize>
|
||||||
<AutoGen>True</AutoGen>
|
</MauiImage>
|
||||||
</Compile>
|
<MauiImage Include="Resources\send.svg">
|
||||||
<Compile Update="Resources\AppResources.de.Designer.cs">
|
<BaseSize>24,24</BaseSize>
|
||||||
<DependentUpon>AppResources.de.resx</DependentUpon>
|
</MauiImage>
|
||||||
<DesignTime>True</DesignTime>
|
<MauiImage Include="Resources\yubikey.png" />
|
||||||
<AutoGen>True</AutoGen>
|
</ItemGroup>
|
||||||
</Compile>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios' AND '$(IncludeBitwardeniOSExtensions)' == 'True'">
|
||||||
<Compile Update="Resources\AppResources.Designer.cs">
|
<ProjectReference Include="..\iOS.Autofill\iOS.Autofill.csproj">
|
||||||
<DesignTime>True</DesignTime>
|
<IsAppExtension>true</IsAppExtension>
|
||||||
<AutoGen>True</AutoGen>
|
<IsWatchApp>false</IsWatchApp>
|
||||||
<DependentUpon>AppResources.resx</DependentUpon>
|
</ProjectReference>
|
||||||
</Compile>
|
<ProjectReference Include="..\iOS.Extension\iOS.Extension.csproj">
|
||||||
<Compile Update="Resources\AppResources.es.Designer.cs">
|
<IsAppExtension>true</IsAppExtension>
|
||||||
<DependentUpon>AppResources.es.resx</DependentUpon>
|
<IsWatchApp>false</IsWatchApp>
|
||||||
<DesignTime>True</DesignTime>
|
</ProjectReference>
|
||||||
<AutoGen>True</AutoGen>
|
<ProjectReference Include="..\iOS.ShareExtension\iOS.ShareExtension.csproj">
|
||||||
</Compile>
|
<IsAppExtension>true</IsAppExtension>
|
||||||
<Compile Update="Resources\AppResources.fi.Designer.cs">
|
<IsWatchApp>false</IsWatchApp>
|
||||||
<DependentUpon>AppResources.fi.resx</DependentUpon>
|
</ProjectReference>
|
||||||
<DesignTime>True</DesignTime>
|
</ItemGroup>
|
||||||
<AutoGen>True</AutoGen>
|
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND '$(IncludeBitwardenWatchOSApp)' == 'True'">
|
||||||
</Compile>
|
<WatchAppBuildPath Condition=" '$(Configuration)' == 'Debug' ">$(Home)/Library/Developer/Xcode/DerivedData/bitwarden-acgkbpwvmebfiofokotvoerzkqcl/Build/Products</WatchAppBuildPath>
|
||||||
<Compile Update="Resources\AppResources.fr.Designer.cs">
|
<WatchAppBuildPath Condition=" '$(Configuration)' != 'Debug' ">$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..'))/watchOS/bitwarden.xcarchive/Products/Applications/bitwarden.app/Watch</WatchAppBuildPath>
|
||||||
<DependentUpon>AppResources.fr.resx</DependentUpon>
|
<WatchAppBundle>Bitwarden.app</WatchAppBundle>
|
||||||
<DesignTime>True</DesignTime>
|
<WatchAppConfiguration Condition="'$(RuntimeIdentifier)'!='ios-arm64'">watchsimulator</WatchAppConfiguration>
|
||||||
<AutoGen>True</AutoGen>
|
<WatchAppConfiguration Condition="'$(RuntimeIdentifier)'=='ios-arm64'">watchos</WatchAppConfiguration>
|
||||||
</Compile>
|
<WatchAppBundleFullPath Condition=" '$(Configuration)' == 'Debug' ">$(WatchAppBuildPath)/$(Configuration)-$(WatchAppConfiguration)/$(WatchAppBundle)</WatchAppBundleFullPath>
|
||||||
<Compile Update="Resources\AppResources.hi.Designer.cs">
|
<WatchAppBundleFullPath Condition=" '$(Configuration)' != 'Debug' ">$(WatchAppBuildPath)/$(WatchAppBundle)</WatchAppBundleFullPath>
|
||||||
<DependentUpon>AppResources.hi.resx</DependentUpon>
|
</PropertyGroup>
|
||||||
<DesignTime>True</DesignTime>
|
<ItemGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND Exists('$(WatchAppBundleFullPath)') ">
|
||||||
<AutoGen>True</AutoGen>
|
<_ResolvedWatchAppReferences Include="$(WatchAppBundleFullPath)" />
|
||||||
</Compile>
|
</ItemGroup>
|
||||||
<Compile Update="Resources\AppResources.hr.Designer.cs">
|
<PropertyGroup Condition="'$(TargetFramework)'=='net8.0-ios' AND Exists('$(WatchAppBundleFullPath)') ">
|
||||||
<DependentUpon>AppResources.hr.resx</DependentUpon>
|
<CreateAppBundleDependsOn>
|
||||||
<DesignTime>True</DesignTime>
|
_CopyWatchOS2AppsToBundle;
|
||||||
<AutoGen>True</AutoGen>
|
$(CreateAppBundleDependsOn);
|
||||||
</Compile>
|
</CreateAppBundleDependsOn>
|
||||||
<Compile Update="Resources\AppResources.hu.Designer.cs">
|
</PropertyGroup>
|
||||||
<DependentUpon>AppResources.hu.resx</DependentUpon>
|
<ItemGroup>
|
||||||
<DesignTime>True</DesignTime>
|
<GoogleServicesJson Include="Platforms\Android\google-services.json" />
|
||||||
<AutoGen>True</AutoGen>
|
<GoogleServicesJson Include="Platforms\Android\google-services.json.enc" />
|
||||||
</Compile>
|
</ItemGroup>
|
||||||
<Compile Update="Resources\AppResources.id.Designer.cs">
|
<ItemGroup>
|
||||||
<DependentUpon>AppResources.id.resx</DependentUpon>
|
<None Remove="Platforms\iOS\Resources\logo.png" />
|
||||||
<DesignTime>True</DesignTime>
|
<None Remove="Platforms\iOS\Resources\logo_white%402x.png" />
|
||||||
<AutoGen>True</AutoGen>
|
<None Remove="Platforms\iOS\Resources\more_vert%402x.png" />
|
||||||
</Compile>
|
<None Remove="Platforms\iOS\Resources\logo_white%403x.png" />
|
||||||
<Compile Update="Resources\AppResources.it.Designer.cs">
|
<None Remove="Platforms\iOS\Resources\logo%403x.png" />
|
||||||
<DependentUpon>AppResources.it.resx</DependentUpon>
|
<None Remove="Platforms\iOS\Resources\more_vert%403x.png" />
|
||||||
<DesignTime>True</DesignTime>
|
<None Remove="Platforms\iOS\Resources\more_vert.png" />
|
||||||
<AutoGen>True</AutoGen>
|
<None Remove="Platforms\iOS\Resources\logo_white.png" />
|
||||||
</Compile>
|
<None Remove="Platforms\iOS\Resources\logo%402x.png" />
|
||||||
<Compile Update="Resources\AppResources.ja.Designer.cs">
|
<None Remove="Platforms\Android\Resources\drawable-xxxhdpi\" />
|
||||||
<DependentUpon>AppResources.ja.resx</DependentUpon>
|
<None Remove="Resources\Raw\" />
|
||||||
<DesignTime>True</DesignTime>
|
</ItemGroup>
|
||||||
<AutoGen>True</AutoGen>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
|
||||||
</Compile>
|
<BundleResource Include="Platforms\iOS\PrivacyInfo.xcprivacy" LogicalName="PrivacyInfo.xcprivacy" />
|
||||||
<Compile Update="Resources\AppResources.nl.Designer.cs">
|
</ItemGroup>
|
||||||
<DependentUpon>AppResources.nl.resx</DependentUpon>
|
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
|
||||||
<DesignTime>True</DesignTime>
|
<MauiAsset Include="Resources\Raw\fido2_privileged_allow_list.json" LogicalName="fido2_privileged_allow_list.json" />
|
||||||
<AutoGen>True</AutoGen>
|
</ItemGroup>
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.pl.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.pl.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.pt-BR.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.pt-BR.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.pt-PT.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.pt-PT.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.ro.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.ro.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.ru.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.ru.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.sk.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.sk.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.sv.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.sv.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.th.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.th.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.tr.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.tr.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.uk.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.uk.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.vi.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.vi.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.zh-Hans.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.zh-Hans.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Resources\AppResources.zh-Hant.Designer.cs">
|
|
||||||
<DependentUpon>AppResources.zh-Hant.resx</DependentUpon>
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.cs.resx">
|
|
||||||
<LastGenOutput>AppResources.cs.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.da.resx">
|
|
||||||
<LastGenOutput>AppResources.da.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.de.resx">
|
|
||||||
<LastGenOutput>AppResources.de.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.es.resx">
|
|
||||||
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.fi.resx">
|
|
||||||
<LastGenOutput>AppResources.fi.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.fr.resx">
|
|
||||||
<LastGenOutput>AppResources.fr.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.hi.resx">
|
|
||||||
<LastGenOutput>AppResources.hi.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.hr.resx">
|
|
||||||
<LastGenOutput>AppResources.hr.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.hu.resx">
|
|
||||||
<LastGenOutput>AppResources.hu.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.id.resx">
|
|
||||||
<LastGenOutput>AppResources.id.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.it.resx">
|
|
||||||
<LastGenOutput>AppResources.it.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.ja.resx">
|
|
||||||
<LastGenOutput>AppResources.ja.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.nl.resx">
|
|
||||||
<LastGenOutput>AppResources.nl.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.pl.resx">
|
|
||||||
<LastGenOutput>AppResources.pl.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.pt-BR.resx">
|
|
||||||
<LastGenOutput>AppResources.pt-BR.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.pt-PT.resx">
|
|
||||||
<LastGenOutput>AppResources.pt-PT.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.resx">
|
|
||||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
|
||||||
<LastGenOutput>AppResources.Designer.cs</LastGenOutput>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.ro.resx">
|
|
||||||
<LastGenOutput>AppResources.ro.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.ru.resx">
|
|
||||||
<LastGenOutput>AppResources.ru.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.sk.resx">
|
|
||||||
<LastGenOutput>AppResources.sk.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.sv.resx">
|
|
||||||
<LastGenOutput>AppResources.sv.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.th.resx">
|
|
||||||
<LastGenOutput>AppResources.th.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.tr.resx">
|
|
||||||
<LastGenOutput>AppResources.tr.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.uk.resx">
|
|
||||||
<LastGenOutput>AppResources.uk.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.vi.resx">
|
|
||||||
<LastGenOutput>AppResources.vi.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.zh-Hans.resx">
|
|
||||||
<LastGenOutput>AppResources.zh-Hans.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Update="Resources\AppResources.zh-Hant.resx">
|
|
||||||
<LastGenOutput>AppResources.zh-Hant.Designer.cs</LastGenOutput>
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="Behaviors\" />
|
|
||||||
<None Remove="Xamarin.CommunityToolkit" />
|
|
||||||
<None Remove="Lists\" />
|
|
||||||
<None Remove="Lists\DataTemplates\" />
|
|
||||||
<None Remove="Lists\DataTemplateSelectors\" />
|
|
||||||
<None Remove="Lists\DataTemplates\CustomFields\" />
|
|
||||||
<None Remove="Lists\ItemViewModels\" />
|
|
||||||
<None Remove="Lists\ItemViewModels\CustomFields\" />
|
|
||||||
<None Remove="Controls\AccountSwitchingOverlay\" />
|
|
||||||
<None Remove="Utilities\AccountManagement\" />
|
|
||||||
<None Remove="Controls\DateTime\" />
|
|
||||||
<None Remove="Controls\IconLabelButton\" />
|
|
||||||
<None Remove="MessagePack" />
|
|
||||||
<None Remove="MessagePack.MSBuild.Tasks" />
|
|
||||||
<None Remove="Controls\PasswordStrengthProgressBar\" />
|
|
||||||
<None Remove="Utilities\Automation\" />
|
|
||||||
<None Remove="Utilities\Prompts\" />
|
|
||||||
<None Remove="Controls\Settings\" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,543 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Models;
|
|
||||||
using Bit.App.Pages;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.App.Services;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.App.Utilities.AccountManagement;
|
|
||||||
using Bit.Core;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Enums;
|
|
||||||
using Bit.Core.Models.Data;
|
|
||||||
using Bit.Core.Models.Response;
|
|
||||||
using Bit.Core.Services;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.Xaml;
|
|
||||||
|
|
||||||
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
|
|
||||||
namespace Bit.App
|
|
||||||
{
|
|
||||||
public partial class App : Application, IAccountsManagerHost
|
|
||||||
{
|
|
||||||
public const string POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE = "popAllAndGoToTabGenerator";
|
|
||||||
public const string POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE = "popAllAndGoToTabMyVault";
|
|
||||||
public const string POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE = "popAllAndGoToTabSend";
|
|
||||||
public const string POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE = "popAllAndGoToAutofillCiphers";
|
|
||||||
|
|
||||||
private readonly IBroadcasterService _broadcasterService;
|
|
||||||
private readonly IMessagingService _messagingService;
|
|
||||||
private readonly IStateService _stateService;
|
|
||||||
private readonly IVaultTimeoutService _vaultTimeoutService;
|
|
||||||
private readonly ISyncService _syncService;
|
|
||||||
private readonly IAuthService _authService;
|
|
||||||
private readonly IDeviceActionService _deviceActionService;
|
|
||||||
private readonly IFileService _fileService;
|
|
||||||
private readonly IAccountsManager _accountsManager;
|
|
||||||
private readonly IPushNotificationService _pushNotificationService;
|
|
||||||
private readonly IConfigService _configService;
|
|
||||||
private static bool _isResumed;
|
|
||||||
// these variables are static because the app is launching new activities on notification click, creating new instances of App.
|
|
||||||
private static bool _pendingCheckPasswordlessLoginRequests;
|
|
||||||
private static object _processingLoginRequestLock = new object();
|
|
||||||
|
|
||||||
public App(AppOptions appOptions)
|
|
||||||
{
|
|
||||||
Options = appOptions ?? new AppOptions();
|
|
||||||
if (Options.IosExtension)
|
|
||||||
{
|
|
||||||
Current = this;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
|
|
||||||
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
|
|
||||||
_authService = ServiceContainer.Resolve<IAuthService>("authService");
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_fileService = ServiceContainer.Resolve<IFileService>();
|
|
||||||
_accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
|
|
||||||
_pushNotificationService = ServiceContainer.Resolve<IPushNotificationService>();
|
|
||||||
_configService = ServiceContainer.Resolve<IConfigService>();
|
|
||||||
|
|
||||||
_accountsManager.Init(() => Options, this);
|
|
||||||
|
|
||||||
Bootstrap();
|
|
||||||
_broadcasterService.Subscribe(nameof(App), async (message) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (message.Command == "showDialog")
|
|
||||||
{
|
|
||||||
var details = message.Data as DialogDetails;
|
|
||||||
var confirmed = true;
|
|
||||||
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ?
|
|
||||||
AppResources.Ok : details.ConfirmText;
|
|
||||||
Device.BeginInvokeOnMainThread(async () =>
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(details.CancelText))
|
|
||||||
{
|
|
||||||
confirmed = await Current.MainPage.DisplayAlert(details.Title, details.Text, confirmText,
|
|
||||||
details.CancelText);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Current.MainPage.DisplayAlert(details.Title, details.Text, confirmText);
|
|
||||||
}
|
|
||||||
_messagingService.Send("showDialogResolve", new Tuple<int, bool>(details.DialogId, confirmed));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (message.Command == AppHelpers.RESUMED_MESSAGE_COMMAND)
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
ResumedAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (message.Command == "slept")
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
await SleptAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (message.Command == "migrated")
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
await _accountsManager.NavigateOnAccountChangeAsync();
|
|
||||||
}
|
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE ||
|
|
||||||
message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE ||
|
|
||||||
message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE ||
|
|
||||||
message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE ||
|
|
||||||
message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
|
||||||
{
|
|
||||||
if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
|
||||||
{
|
|
||||||
Options.OtpData = new OtpData((string)message.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Device.InvokeOnMainThreadAsync(async () =>
|
|
||||||
{
|
|
||||||
if (Current.MainPage is TabsPage tabsPage)
|
|
||||||
{
|
|
||||||
while (tabsPage.Navigation.ModalStack.Count > 0)
|
|
||||||
{
|
|
||||||
await tabsPage.Navigation.PopModalAsync(false);
|
|
||||||
}
|
|
||||||
if (message.Command == POP_ALL_AND_GO_TO_AUTOFILL_CIPHERS_MESSAGE)
|
|
||||||
{
|
|
||||||
Current.MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
|
||||||
}
|
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_MYVAULT_MESSAGE)
|
|
||||||
{
|
|
||||||
Options.MyVaultTile = false;
|
|
||||||
tabsPage.ResetToVaultPage();
|
|
||||||
}
|
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_GENERATOR_MESSAGE)
|
|
||||||
{
|
|
||||||
Options.GeneratorTile = false;
|
|
||||||
tabsPage.ResetToGeneratorPage();
|
|
||||||
}
|
|
||||||
else if (message.Command == POP_ALL_AND_GO_TO_TAB_SEND_MESSAGE)
|
|
||||||
{
|
|
||||||
tabsPage.ResetToSendPage();
|
|
||||||
}
|
|
||||||
else if (message.Command == DeepLinkContext.NEW_OTP_MESSAGE)
|
|
||||||
{
|
|
||||||
tabsPage.ResetToVaultPage();
|
|
||||||
await tabsPage.Navigation.PushModalAsync(new NavigationPage(new CipherSelectionPage(Options)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (message.Command == "convertAccountToKeyConnector")
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(async () =>
|
|
||||||
{
|
|
||||||
await Application.Current.MainPage.Navigation.PushModalAsync(
|
|
||||||
new NavigationPage(new RemoveMasterPasswordPage()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (message.Command == Constants.ForceUpdatePassword)
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(async () =>
|
|
||||||
{
|
|
||||||
await Application.Current.MainPage.Navigation.PushModalAsync(
|
|
||||||
new NavigationPage(new UpdateTempPasswordPage()));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (message.Command == Constants.ForceSetPassword)
|
|
||||||
{
|
|
||||||
await Device.InvokeOnMainThreadAsync(() => Application.Current.MainPage.Navigation.PushModalAsync(
|
|
||||||
new NavigationPage(new SetPasswordPage(orgIdentifier: (string)message.Data))));
|
|
||||||
}
|
|
||||||
else if (message.Command == "syncCompleted")
|
|
||||||
{
|
|
||||||
await _configService.GetAsync(true);
|
|
||||||
}
|
|
||||||
else if (message.Command == Constants.PasswordlessLoginRequestKey
|
|
||||||
|| message.Command == "unlocked"
|
|
||||||
|| message.Command == AccountsManagerMessageCommands.ACCOUNT_SWITCH_COMPLETED)
|
|
||||||
{
|
|
||||||
lock (_processingLoginRequestLock)
|
|
||||||
{
|
|
||||||
// lock doesn't allow for async execution
|
|
||||||
CheckPasswordlessLoginRequestsAsync().Wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CheckPasswordlessLoginRequestsAsync()
|
|
||||||
{
|
|
||||||
if (!_isResumed)
|
|
||||||
{
|
|
||||||
_pendingCheckPasswordlessLoginRequests = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_pendingCheckPasswordlessLoginRequests = false;
|
|
||||||
if (await _vaultTimeoutService.IsLockedAsync())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var notification = await _stateService.GetPasswordlessLoginNotificationAsync();
|
|
||||||
if (notification == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await CheckShouldSwitchActiveUserAsync(notification))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay to wait for the vault page to appear
|
|
||||||
await Task.Delay(2000);
|
|
||||||
// if there is a request modal opened ignore all incoming requests
|
|
||||||
if (App.Current.MainPage.Navigation.ModalStack.Any(p => p is NavigationPage navPage && navPage.CurrentPage is LoginPasswordlessPage))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var loginRequestData = await _authService.GetPasswordlessLoginRequestByIdAsync(notification.Id);
|
|
||||||
var page = new LoginPasswordlessPage(new LoginPasswordlessDetails()
|
|
||||||
{
|
|
||||||
PubKey = loginRequestData.PublicKey,
|
|
||||||
Id = loginRequestData.Id,
|
|
||||||
IpAddress = loginRequestData.RequestIpAddress,
|
|
||||||
Email = await _stateService.GetEmailAsync(),
|
|
||||||
FingerprintPhrase = loginRequestData.FingerprintPhrase,
|
|
||||||
RequestDate = loginRequestData.CreationDate,
|
|
||||||
DeviceType = loginRequestData.RequestDeviceType,
|
|
||||||
Origin = loginRequestData.Origin
|
|
||||||
});
|
|
||||||
await _stateService.SetPasswordlessLoginNotificationAsync(null);
|
|
||||||
_pushNotificationService.DismissLocalNotification(Constants.PasswordlessNotificationId);
|
|
||||||
if (!loginRequestData.IsExpired)
|
|
||||||
{
|
|
||||||
await Device.InvokeOnMainThreadAsync(() => Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(page)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> CheckShouldSwitchActiveUserAsync(PasswordlessRequestNotification notification)
|
|
||||||
{
|
|
||||||
var activeUserId = await _stateService.GetActiveUserIdAsync();
|
|
||||||
if (notification.UserId == activeUserId)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var notificationUserEmail = await _stateService.GetEmailAsync(notification.UserId);
|
|
||||||
Device.BeginInvokeOnMainThread(async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var result = await _deviceActionService.DisplayAlertAsync(AppResources.LogInRequested, string.Format(AppResources.LoginAttemptFromXDoYouWantToSwitchToThisAccount, notificationUserEmail), AppResources.Cancel, AppResources.Ok);
|
|
||||||
if (result == AppResources.Ok)
|
|
||||||
{
|
|
||||||
await _stateService.SetActiveUserAsync(notification.UserId);
|
|
||||||
_messagingService.Send(AccountsManagerMessageCommands.SWITCHED_ACCOUNT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LoggerHelper.LogEvenIfCantBeResolved(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AppOptions Options { get; private set; }
|
|
||||||
|
|
||||||
protected async override void OnStart()
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine("XF App: OnStart");
|
|
||||||
_isResumed = true;
|
|
||||||
await ClearCacheIfNeededAsync();
|
|
||||||
Prime();
|
|
||||||
if (string.IsNullOrWhiteSpace(Options.Uri))
|
|
||||||
{
|
|
||||||
var updated = await AppHelpers.PerformUpdateTasksAsync(_syncService, _deviceActionService,
|
|
||||||
_stateService);
|
|
||||||
if (!updated)
|
|
||||||
{
|
|
||||||
SyncIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (_pendingCheckPasswordlessLoginRequests)
|
|
||||||
{
|
|
||||||
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
|
|
||||||
}
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
|
||||||
// Reset delay on every start
|
|
||||||
_vaultTimeoutService.DelayLockAndLogoutMs = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _configService.GetAsync();
|
|
||||||
_messagingService.Send("startEventTimer");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async override void OnSleep()
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine("XF App: OnSleep");
|
|
||||||
_isResumed = false;
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
var isLocked = await _vaultTimeoutService.IsLockedAsync();
|
|
||||||
if (!isLocked)
|
|
||||||
{
|
|
||||||
await _stateService.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime());
|
|
||||||
}
|
|
||||||
if (!SetTabsPageFromAutofill(isLocked))
|
|
||||||
{
|
|
||||||
ClearAutofillUri();
|
|
||||||
}
|
|
||||||
await SleptAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnResume()
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.WriteLine("XF App: OnResume");
|
|
||||||
_isResumed = true;
|
|
||||||
if (_pendingCheckPasswordlessLoginRequests)
|
|
||||||
{
|
|
||||||
_messagingService.Send(Constants.PasswordlessLoginRequestKey);
|
|
||||||
}
|
|
||||||
if (Device.RuntimePlatform == Device.Android)
|
|
||||||
{
|
|
||||||
ResumedAsync().FireAndForget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SleptAsync()
|
|
||||||
{
|
|
||||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
|
||||||
await ClearSensitiveFieldsAsync();
|
|
||||||
_messagingService.Send("stopEventTimer");
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ResumedAsync()
|
|
||||||
{
|
|
||||||
await _stateService.CheckExtensionActiveUserAndSwitchIfNeededAsync();
|
|
||||||
await _vaultTimeoutService.CheckVaultTimeoutAsync();
|
|
||||||
await ClearSensitiveFieldsAsync();
|
|
||||||
_messagingService.Send("startEventTimer");
|
|
||||||
await UpdateThemeAsync();
|
|
||||||
await ClearCacheIfNeededAsync();
|
|
||||||
Prime();
|
|
||||||
SyncIfNeeded();
|
|
||||||
if (Current.MainPage is NavigationPage navPage && navPage.CurrentPage is LockPage lockPage)
|
|
||||||
{
|
|
||||||
await lockPage.PromptBiometricAfterResumeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateThemeAsync()
|
|
||||||
{
|
|
||||||
await Device.InvokeOnMainThreadAsync(() =>
|
|
||||||
{
|
|
||||||
ThemeManager.SetTheme(Current.Resources);
|
|
||||||
_messagingService.Send(ThemeManager.UPDATED_THEME_MESSAGE_KEY);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ClearSensitiveFieldsAsync()
|
|
||||||
{
|
|
||||||
await Device.InvokeOnMainThreadAsync(() =>
|
|
||||||
{
|
|
||||||
_messagingService.Send(Constants.ClearSensitiveFields);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetCulture()
|
|
||||||
{
|
|
||||||
// Calendars are removed by linker. ref https://bugzilla.xamarin.com/show_bug.cgi?id=59077
|
|
||||||
new System.Globalization.ThaiBuddhistCalendar();
|
|
||||||
new System.Globalization.HijriCalendar();
|
|
||||||
new System.Globalization.UmAlQuraCalendar();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ClearCacheIfNeededAsync()
|
|
||||||
{
|
|
||||||
var lastClear = await _stateService.GetLastFileCacheClearAsync();
|
|
||||||
if ((DateTime.UtcNow - lastClear.GetValueOrDefault(DateTime.MinValue)).TotalDays >= 1)
|
|
||||||
{
|
|
||||||
var task = Task.Run(() => _fileService.ClearCacheAsync());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearAutofillUri()
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.Android && !string.IsNullOrWhiteSpace(Options.Uri))
|
|
||||||
{
|
|
||||||
Options.Uri = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool SetTabsPageFromAutofill(bool isLocked)
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.Android && !string.IsNullOrWhiteSpace(Options.Uri) &&
|
|
||||||
!Options.FromAutofillFramework)
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
Device.BeginInvokeOnMainThread(() =>
|
|
||||||
{
|
|
||||||
Options.Uri = null;
|
|
||||||
if (isLocked)
|
|
||||||
{
|
|
||||||
Current.MainPage = new NavigationPage(new LockPage());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Current.MainPage = new TabsPage();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Prime()
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
var word = EEFLongWordList.Instance.List[1];
|
|
||||||
var parsedDomain = DomainName.TryParse("https://bitwarden.com", out var domainName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Bootstrap()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
SetCulture();
|
|
||||||
ThemeManager.SetTheme(Current.Resources);
|
|
||||||
Current.RequestedThemeChanged += (s, a) =>
|
|
||||||
{
|
|
||||||
UpdateThemeAsync();
|
|
||||||
};
|
|
||||||
Current.MainPage = new NavigationPage(new HomePage(Options));
|
|
||||||
_accountsManager.NavigateOnAccountChangeAsync().FireAndForget();
|
|
||||||
ServiceContainer.Resolve<MobilePlatformUtilsService>("platformUtilsService").Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SyncIfNeeded()
|
|
||||||
{
|
|
||||||
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
var lastSync = await _syncService.GetLastSyncAsync();
|
|
||||||
if (lastSync == null || ((DateTime.UtcNow - lastSync) > TimeSpan.FromMinutes(30)))
|
|
||||||
{
|
|
||||||
await Task.Delay(1000);
|
|
||||||
await _syncService.FullSyncAsync(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SetPreviousPageInfoAsync()
|
|
||||||
{
|
|
||||||
PreviousPageInfo lastPageBeforeLock = null;
|
|
||||||
if (Current.MainPage is TabbedPage tabbedPage && tabbedPage.Navigation.ModalStack.Count > 0)
|
|
||||||
{
|
|
||||||
var topPage = tabbedPage.Navigation.ModalStack[tabbedPage.Navigation.ModalStack.Count - 1];
|
|
||||||
if (topPage is NavigationPage navPage)
|
|
||||||
{
|
|
||||||
if (navPage.CurrentPage is CipherDetailsPage cipherDetailsPage)
|
|
||||||
{
|
|
||||||
lastPageBeforeLock = new PreviousPageInfo
|
|
||||||
{
|
|
||||||
Page = "view",
|
|
||||||
CipherId = cipherDetailsPage.ViewModel.CipherId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (navPage.CurrentPage is CipherAddEditPage cipherAddEditPage && cipherAddEditPage.ViewModel.EditMode)
|
|
||||||
{
|
|
||||||
lastPageBeforeLock = new PreviousPageInfo
|
|
||||||
{
|
|
||||||
Page = "edit",
|
|
||||||
CipherId = cipherAddEditPage.ViewModel.CipherId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await _stateService.SetPreviousPageInfoAsync(lastPageBeforeLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Navigate(NavigationTarget navTarget, INavigationParams navParams)
|
|
||||||
{
|
|
||||||
switch (navTarget)
|
|
||||||
{
|
|
||||||
case NavigationTarget.HomeLogin:
|
|
||||||
Current.MainPage = new NavigationPage(new HomePage(Options));
|
|
||||||
break;
|
|
||||||
case NavigationTarget.Login:
|
|
||||||
if (navParams is LoginNavigationParams loginParams)
|
|
||||||
{
|
|
||||||
Current.MainPage = new NavigationPage(new LoginPage(loginParams.Email, Options));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NavigationTarget.Lock:
|
|
||||||
if (navParams is LockNavigationParams lockParams)
|
|
||||||
{
|
|
||||||
Current.MainPage = new NavigationPage(new LockPage(Options, lockParams.AutoPromptBiometric));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Current.MainPage = new NavigationPage(new LockPage(Options));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NavigationTarget.Home:
|
|
||||||
Current.MainPage = new TabsPage(Options);
|
|
||||||
break;
|
|
||||||
case NavigationTarget.AddEditCipher:
|
|
||||||
Current.MainPage = new NavigationPage(new CipherAddEditPage(appOptions: Options));
|
|
||||||
break;
|
|
||||||
case NavigationTarget.AutofillCiphers:
|
|
||||||
case NavigationTarget.OtpCipherSelection:
|
|
||||||
Current.MainPage = new NavigationPage(new CipherSelectionPage(Options));
|
|
||||||
break;
|
|
||||||
case NavigationTarget.SendAddEdit:
|
|
||||||
Current.MainPage = new NavigationPage(new SendAddEditPage(Options));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Bit.App.Pages;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public partial class AuthenticatorViewCell : ExtendedGrid
|
|
||||||
{
|
|
||||||
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
|
|
||||||
nameof(Cipher), typeof(CipherView), typeof(AuthenticatorViewCell), default(CipherView), BindingMode.TwoWay);
|
|
||||||
|
|
||||||
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
|
|
||||||
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(AuthenticatorViewCell));
|
|
||||||
|
|
||||||
public static readonly BindableProperty TotpSecProperty = BindableProperty.Create(
|
|
||||||
nameof(TotpSec), typeof(long), typeof(AuthenticatorViewCell));
|
|
||||||
|
|
||||||
public AuthenticatorViewCell()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Command CopyCommand { get; set; }
|
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => GetValue(CipherProperty) as CipherView;
|
|
||||||
set => SetValue(CipherProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool? WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(WebsiteIconsEnabledProperty);
|
|
||||||
set => SetValue(WebsiteIconsEnabledProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long TotpSec
|
|
||||||
{
|
|
||||||
get => (long)GetValue(TotpSecProperty);
|
|
||||||
set => SetValue(TotpSecProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowIconImage
|
|
||||||
{
|
|
||||||
get => WebsiteIconsEnabled ?? false
|
|
||||||
&& !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
|
|
||||||
&& IconImageSource != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string _iconImageSource = string.Empty;
|
|
||||||
public string IconImageSource
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_iconImageSource == string.Empty) // default value since icon source can return null
|
|
||||||
{
|
|
||||||
_iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
|
|
||||||
}
|
|
||||||
return _iconImageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using SkiaSharp;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class AvatarImageSource : StreamImageSource
|
|
||||||
{
|
|
||||||
private readonly string _text;
|
|
||||||
private readonly string _id;
|
|
||||||
private readonly string _color;
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (obj is null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj is AvatarImageSource avatar)
|
|
||||||
{
|
|
||||||
return avatar._id == _id && avatar._text == _text && avatar._color == _color;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.Equals(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode() => _id?.GetHashCode() ?? _text?.GetHashCode() ?? -1;
|
|
||||||
|
|
||||||
public AvatarImageSource(string userId = null, string name = null, string email = null, string color = null)
|
|
||||||
{
|
|
||||||
_id = userId;
|
|
||||||
_text = name;
|
|
||||||
if (string.IsNullOrWhiteSpace(_text))
|
|
||||||
{
|
|
||||||
_text = email;
|
|
||||||
}
|
|
||||||
_color = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Func<CancellationToken, Task<Stream>> Stream => GetStreamAsync;
|
|
||||||
|
|
||||||
private Task<Stream> GetStreamAsync(CancellationToken userToken = new CancellationToken())
|
|
||||||
{
|
|
||||||
OnLoadingStarted();
|
|
||||||
userToken.Register(CancellationTokenSource.Cancel);
|
|
||||||
var result = Draw();
|
|
||||||
OnLoadingCompleted(CancellationTokenSource.IsCancellationRequested);
|
|
||||||
return Task.FromResult(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Stream Draw()
|
|
||||||
{
|
|
||||||
string chars;
|
|
||||||
string upperCaseText = null;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_text))
|
|
||||||
{
|
|
||||||
chars = "..";
|
|
||||||
}
|
|
||||||
else if (_text?.Length > 1)
|
|
||||||
{
|
|
||||||
upperCaseText = _text.ToUpper();
|
|
||||||
chars = GetFirstLetters(upperCaseText, 2);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chars = upperCaseText = _text.ToUpper();
|
|
||||||
}
|
|
||||||
|
|
||||||
var bgColor = _color ?? CoreHelpers.StringToColor(_id ?? upperCaseText, "#33ffffff");
|
|
||||||
var textColor = CoreHelpers.TextColorFromBgColor(bgColor);
|
|
||||||
var size = 50;
|
|
||||||
|
|
||||||
using (var bitmap = new SKBitmap(size * 2,
|
|
||||||
size * 2,
|
|
||||||
SKImageInfo.PlatformColorType,
|
|
||||||
SKAlphaType.Premul))
|
|
||||||
{
|
|
||||||
using (var canvas = new SKCanvas(bitmap))
|
|
||||||
{
|
|
||||||
canvas.Clear(SKColors.Transparent);
|
|
||||||
using (var paint = new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
Style = SKPaintStyle.Fill,
|
|
||||||
StrokeJoin = SKStrokeJoin.Miter,
|
|
||||||
Color = SKColor.Parse(bgColor)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
var midX = canvas.LocalClipBounds.Size.ToSizeI().Width / 2;
|
|
||||||
var midY = canvas.LocalClipBounds.Size.ToSizeI().Height / 2;
|
|
||||||
var radius = midX - midX / 5;
|
|
||||||
|
|
||||||
using (var circlePaint = new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
Style = SKPaintStyle.Fill,
|
|
||||||
StrokeJoin = SKStrokeJoin.Miter,
|
|
||||||
Color = SKColor.Parse(bgColor)
|
|
||||||
})
|
|
||||||
{
|
|
||||||
canvas.DrawCircle(midX, midY, radius, circlePaint);
|
|
||||||
|
|
||||||
var typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Normal);
|
|
||||||
var textSize = midX / 1.3f;
|
|
||||||
using (var textPaint = new SKPaint
|
|
||||||
{
|
|
||||||
IsAntialias = true,
|
|
||||||
Style = SKPaintStyle.Fill,
|
|
||||||
Color = SKColor.Parse(textColor),
|
|
||||||
TextSize = textSize,
|
|
||||||
TextAlign = SKTextAlign.Center,
|
|
||||||
Typeface = typeface
|
|
||||||
})
|
|
||||||
{
|
|
||||||
var rect = new SKRect();
|
|
||||||
textPaint.MeasureText(chars, ref rect);
|
|
||||||
canvas.DrawText(chars, midX, midY + rect.Height / 2, textPaint);
|
|
||||||
|
|
||||||
using (var img = SKImage.FromBitmap(bitmap))
|
|
||||||
{
|
|
||||||
var data = img.Encode(SKEncodedImageFormat.Png, 100);
|
|
||||||
return data?.AsStream(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetFirstLetters(string data, int charCount)
|
|
||||||
{
|
|
||||||
var sanitizedData = data.Trim();
|
|
||||||
var parts = sanitizedData.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
if (parts.Length > 1 && charCount <= 2)
|
|
||||||
{
|
|
||||||
var text = string.Empty;
|
|
||||||
for (var i = 0; i < charCount; i++)
|
|
||||||
{
|
|
||||||
text += parts[i][0];
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
if (sanitizedData.Length > 2)
|
|
||||||
{
|
|
||||||
return sanitizedData.Substring(0, 2);
|
|
||||||
}
|
|
||||||
return sanitizedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color StringToColor(string str)
|
|
||||||
{
|
|
||||||
if (str == null)
|
|
||||||
{
|
|
||||||
return Color.FromHex("#33ffffff");
|
|
||||||
}
|
|
||||||
var hash = 0;
|
|
||||||
for (var i = 0; i < str.Length; i++)
|
|
||||||
{
|
|
||||||
hash = str[i] + ((hash << 5) - hash);
|
|
||||||
}
|
|
||||||
var color = "#FF";
|
|
||||||
for (var i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
var value = (hash >> (i * 8)) & 0xff;
|
|
||||||
var base16 = "00" + Convert.ToString(value, 16);
|
|
||||||
color += base16.Substring(base16.Length - 2);
|
|
||||||
}
|
|
||||||
return Color.FromHex(color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public partial class CipherViewCell : ExtendedGrid
|
|
||||||
{
|
|
||||||
private const int ICON_COLUMN_DEFAULT_WIDTH = 40;
|
|
||||||
private const int ICON_IMAGE_DEFAULT_WIDTH = 22;
|
|
||||||
|
|
||||||
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
|
|
||||||
nameof(Cipher), typeof(CipherView), typeof(CipherViewCell), default(CipherView), BindingMode.OneWay);
|
|
||||||
|
|
||||||
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
|
|
||||||
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(CipherViewCell));
|
|
||||||
|
|
||||||
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
|
|
||||||
nameof(ButtonCommand), typeof(ICommand), typeof(CipherViewCell));
|
|
||||||
|
|
||||||
public CipherViewCell()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
var fontScale = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService").GetSystemFontSizeScale();
|
|
||||||
_iconColumn.Width = new GridLength(ICON_COLUMN_DEFAULT_WIDTH * fontScale, GridUnitType.Absolute);
|
|
||||||
_iconImage.WidthRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
|
|
||||||
_iconImage.HeightRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool? WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(WebsiteIconsEnabledProperty);
|
|
||||||
set => SetValue(WebsiteIconsEnabledProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => GetValue(CipherProperty) as CipherView;
|
|
||||||
set => SetValue(CipherProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICommand ButtonCommand
|
|
||||||
{
|
|
||||||
get => GetValue(ButtonCommandProperty) as ICommand;
|
|
||||||
set => SetValue(ButtonCommandProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPropertyChanged(string propertyName = null)
|
|
||||||
{
|
|
||||||
base.OnPropertyChanged(propertyName);
|
|
||||||
if (propertyName == CipherProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Cipher == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BindingContext = new CipherViewCellViewModel(Cipher, WebsiteIconsEnabled ?? false);
|
|
||||||
}
|
|
||||||
else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Cipher == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
((CipherViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoreButton_Clicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var cipher = ((sender as MiButton)?.BindingContext as CipherViewCellViewModel)?.Cipher;
|
|
||||||
if (cipher != null)
|
|
||||||
{
|
|
||||||
ButtonCommand?.Execute(cipher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class CipherViewCellViewModel : ExtendedViewModel
|
|
||||||
{
|
|
||||||
private CipherView _cipher;
|
|
||||||
private bool _websiteIconsEnabled;
|
|
||||||
private string _iconImageSource = string.Empty;
|
|
||||||
|
|
||||||
public CipherViewCellViewModel(CipherView cipherView, bool websiteIconsEnabled)
|
|
||||||
{
|
|
||||||
Cipher = cipherView;
|
|
||||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => _cipher;
|
|
||||||
set => SetProperty(ref _cipher, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => _websiteIconsEnabled;
|
|
||||||
set => SetProperty(ref _websiteIconsEnabled, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowIconImage
|
|
||||||
{
|
|
||||||
get => WebsiteIconsEnabled
|
|
||||||
&& !string.IsNullOrWhiteSpace(Cipher.LaunchUri)
|
|
||||||
&& IconImageSource != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string IconImageSource
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_iconImageSource == string.Empty) // default value since icon source can return null
|
|
||||||
{
|
|
||||||
_iconImageSource = IconImageHelper.GetIconImage(Cipher);
|
|
||||||
}
|
|
||||||
return _iconImageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Xamarin.CommunityToolkit.Converters;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedCollectionView : CollectionView
|
|
||||||
{
|
|
||||||
public string ExtraDataForLogging { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SelectionChangedEventArgsConverter : BaseNullableConverterOneWay<SelectionChangedEventArgs, object>
|
|
||||||
{
|
|
||||||
public override object? ConvertFrom(SelectionChangedEventArgs? value)
|
|
||||||
{
|
|
||||||
return value?.CurrentSelection.FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedGrid : Grid
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using Bit.App.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedSearchBar : SearchBar
|
|
||||||
{
|
|
||||||
public ExtendedSearchBar()
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
if (ThemeManager.UsingLightTheme)
|
|
||||||
{
|
|
||||||
TextColor = Color.Black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class ExtendedStackLayout : StackLayout
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Frame xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Controls.IconLabelButton"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
x:Name="_iconLabelButton"
|
|
||||||
HeightRequest="45"
|
|
||||||
Padding="1"
|
|
||||||
StyleClass="btn-icon-secondary"
|
|
||||||
BackgroundColor="{Binding IconLabelBorderColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
BorderColor="Transparent"
|
|
||||||
HasShadow="False">
|
|
||||||
<Frame.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Command="{Binding ButtonCommand, Source={x:Reference _iconLabelButton}}" />
|
|
||||||
</Frame.GestureRecognizers>
|
|
||||||
<Frame
|
|
||||||
Margin="0"
|
|
||||||
Padding="0"
|
|
||||||
CornerRadius="{Binding CornerRadius, Source={x:Reference _iconLabelButton}}"
|
|
||||||
BackgroundColor="{Binding IconLabelBackgroundColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
BorderColor="Transparent"
|
|
||||||
IsClippedToBounds="True"
|
|
||||||
HasShadow="False">
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
HorizontalOptions="Center">
|
|
||||||
<controls:IconLabel
|
|
||||||
VerticalOptions="Center"
|
|
||||||
HorizontalTextAlignment="Center"
|
|
||||||
FontSize="Large"
|
|
||||||
TextColor="{Binding IconLabelColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
Text="{Binding Icon, Source={x:Reference _iconLabelButton}}">
|
|
||||||
</controls:IconLabel>
|
|
||||||
<Label
|
|
||||||
VerticalOptions="Center"
|
|
||||||
HorizontalTextAlignment="Center"
|
|
||||||
TextColor="{Binding IconLabelColor, Source={x:Reference _iconLabelButton}}"
|
|
||||||
FontSize="Medium"
|
|
||||||
Text="{Binding Label, Source={x:Reference _iconLabelButton}}"/>
|
|
||||||
</StackLayout>
|
|
||||||
</Frame>
|
|
||||||
</Frame>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class MonoEntry : Entry
|
|
||||||
{
|
|
||||||
public MonoEntry()
|
|
||||||
{
|
|
||||||
switch (Device.RuntimePlatform)
|
|
||||||
{
|
|
||||||
case Device.iOS:
|
|
||||||
FontFamily = "Menlo-Regular";
|
|
||||||
break;
|
|
||||||
case Device.Android:
|
|
||||||
FontFamily = "RobotoMono_Regular.ttf#Roboto Mono";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public class MonoLabel : Label
|
|
||||||
{
|
|
||||||
public MonoLabel()
|
|
||||||
{
|
|
||||||
switch (Device.RuntimePlatform)
|
|
||||||
{
|
|
||||||
case Device.iOS:
|
|
||||||
FontFamily = "Menlo-Regular";
|
|
||||||
break;
|
|
||||||
case Device.Android:
|
|
||||||
FontFamily = "RobotoMono_Regular.ttf#Roboto Mono";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Controls
|
|
||||||
{
|
|
||||||
public partial class SendViewCell : ExtendedGrid
|
|
||||||
{
|
|
||||||
public static readonly BindableProperty SendProperty = BindableProperty.Create(
|
|
||||||
nameof(Send), typeof(SendView), typeof(SendViewCell), default(SendView), BindingMode.OneWay);
|
|
||||||
|
|
||||||
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
|
|
||||||
nameof(ButtonCommand), typeof(Command<SendView>), typeof(SendViewCell));
|
|
||||||
|
|
||||||
public static readonly BindableProperty ShowOptionsProperty = BindableProperty.Create(
|
|
||||||
nameof(ShowOptions), typeof(bool), typeof(SendViewCell), true, BindingMode.OneWay);
|
|
||||||
|
|
||||||
public SendViewCell()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
_iconColumn.Width = new GridLength(40 * deviceActionService.GetSystemFontSizeScale(), GridUnitType.Absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SendView Send
|
|
||||||
{
|
|
||||||
get => GetValue(SendProperty) as SendView;
|
|
||||||
set => SetValue(SendProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Command<SendView> ButtonCommand
|
|
||||||
{
|
|
||||||
get => GetValue(ButtonCommandProperty) as Command<SendView>;
|
|
||||||
set => SetValue(ButtonCommandProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowOptions
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(ShowOptionsProperty);
|
|
||||||
set => SetValue(ShowOptionsProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnPropertyChanged(string propertyName = null)
|
|
||||||
{
|
|
||||||
base.OnPropertyChanged(propertyName);
|
|
||||||
if (propertyName == SendProperty.PropertyName)
|
|
||||||
{
|
|
||||||
if (Send == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BindingContext = new SendViewCellViewModel(Send, ShowOptions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoreButton_Clicked(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var send = ((sender as MiButton)?.BindingContext as SendViewCellViewModel)?.Send;
|
|
||||||
if (send != null)
|
|
||||||
{
|
|
||||||
ButtonCommand?.Execute(send);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class FabShadowEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public FabShadowEffect()
|
|
||||||
: base("Bitwarden.FabShadowEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class FixedSizeEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public FixedSizeEffect()
|
|
||||||
: base("Bitwarden.FixedSizeEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class NoEmojiKeyboardEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public NoEmojiKeyboardEffect()
|
|
||||||
: base("Bitwarden.NoEmojiKeyboardEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class RemoveFontPaddingEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public RemoveFontPaddingEffect()
|
|
||||||
: base("Bitwarden.RemoveFontPaddingEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public enum ScrollContentInsetAdjustmentBehavior
|
|
||||||
{
|
|
||||||
Automatic,
|
|
||||||
ScrollableAxes,
|
|
||||||
Never,
|
|
||||||
Always
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ScrollViewContentInsetAdjustmentBehaviorEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public static readonly BindableProperty ContentInsetAdjustmentBehaviorProperty =
|
|
||||||
BindableProperty.CreateAttached("ContentInsetAdjustmentBehavior", typeof(ScrollContentInsetAdjustmentBehavior), typeof(ScrollViewContentInsetAdjustmentBehaviorEffect), ScrollContentInsetAdjustmentBehavior.Automatic);
|
|
||||||
|
|
||||||
public static ScrollContentInsetAdjustmentBehavior GetContentInsetAdjustmentBehavior(BindableObject view)
|
|
||||||
{
|
|
||||||
return (ScrollContentInsetAdjustmentBehavior)view.GetValue(ContentInsetAdjustmentBehaviorProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetContentInsetAdjustmentBehavior(BindableObject view, ScrollContentInsetAdjustmentBehavior value)
|
|
||||||
{
|
|
||||||
view.SetValue(ContentInsetAdjustmentBehaviorProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScrollViewContentInsetAdjustmentBehaviorEffect()
|
|
||||||
: base($"Bitwarden.{nameof(ScrollViewContentInsetAdjustmentBehaviorEffect)}")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Effects
|
|
||||||
{
|
|
||||||
public class TabBarEffect : RoutingEffect
|
|
||||||
{
|
|
||||||
public TabBarEffect()
|
|
||||||
: base("Bitwarden.TabBarEffect")
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
41
src/App/MauiProgram.cs
Normal file
41
src/App/MauiProgram.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
namespace Bit.App
|
||||||
|
{
|
||||||
|
public class MauiProgram
|
||||||
|
{
|
||||||
|
public static MauiApp CreateMauiApp()
|
||||||
|
{
|
||||||
|
return Core.MauiProgram.ConfigureMauiAppBuilder(
|
||||||
|
effects =>
|
||||||
|
{
|
||||||
|
#if IOS
|
||||||
|
iOS.Core.Utilities.iOSCoreHelpers.ConfigureMAUIEffects(effects);
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
handlers =>
|
||||||
|
{
|
||||||
|
#if ANDROID
|
||||||
|
Bit.App.Handlers.EntryHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.EditorHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.LabelHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.PickerHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.SearchBarHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.SwitchHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.DatePickerHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.SliderHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.StepperHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.TimePickerHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.ButtonHandlerMappings.Setup();
|
||||||
|
Bit.App.Handlers.ToolbarHandlerMappings.Setup();
|
||||||
|
|
||||||
|
handlers.AddHandler(typeof(Bit.App.Controls.HybridWebView), typeof(Bit.App.Handlers.HybridWebViewHandler));
|
||||||
|
handlers.AddHandler(typeof(Bit.App.Pages.TabsPage), typeof(Bit.App.Handlers.CustomTabbedPageHandler));
|
||||||
|
handlers.AddHandler(typeof(Bit.App.Controls.ExtendedDatePicker), typeof(Bit.App.Handlers.ExtendedDatePickerHandler));
|
||||||
|
#else
|
||||||
|
iOS.Core.Utilities.iOSCoreHelpers.ConfigureMAUIHandlers(handlers);
|
||||||
|
#endif
|
||||||
|
},
|
||||||
|
initUseMauiApp: true
|
||||||
|
).Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
x:Class="Bit.App.Pages.HomePage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
x:DataType="pages:HomeViewModel"
|
|
||||||
x:Name="_page"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:HomeViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ContentPage.ToolbarItems>
|
|
||||||
<controls:ExtendedToolbarItem
|
|
||||||
x:Name="_accountAvatar"
|
|
||||||
x:Key="accountAvatar"
|
|
||||||
IconImageSource="{Binding AvatarImageSource}"
|
|
||||||
Command="{Binding Source={x:Reference _accountListOverlay}, Path=ToggleVisibililtyCommand}"
|
|
||||||
Order="Primary"
|
|
||||||
Priority="-1"
|
|
||||||
UseOriginalImage="True"
|
|
||||||
AutomationProperties.IsInAccessibleTree="True"
|
|
||||||
AutomationProperties.Name="{u:I18n Account}"
|
|
||||||
AutomationId="AccountIconButton" />
|
|
||||||
<ToolbarItem x:Name="_closeButton" Text="{u:I18n Close}" Command="{Binding CloseCommand}" Order="Primary" Priority="-1"/>
|
|
||||||
</ContentPage.ToolbarItems>
|
|
||||||
|
|
||||||
<ContentPage.Resources>
|
|
||||||
<ResourceDictionary>
|
|
||||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
|
||||||
<StackLayout x:Name="_mainLayout" x:Key="mainLayout" Spacing="30" Padding="20, 50, 20, 0">
|
|
||||||
<Image
|
|
||||||
x:Name="_logo"
|
|
||||||
Source="logo.png"
|
|
||||||
VerticalOptions="Center" />
|
|
||||||
<Label Text="{u:I18n LoginOrCreateNewAccount}"
|
|
||||||
StyleClass="text-lg"
|
|
||||||
HorizontalTextAlignment="Center"/>
|
|
||||||
<StackLayout
|
|
||||||
StyleClass="box-row">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n EmailAddress}"
|
|
||||||
StyleClass="box-label" />
|
|
||||||
<Entry
|
|
||||||
x:Name="_email"
|
|
||||||
Text="{Binding Email}"
|
|
||||||
Keyboard="Email"
|
|
||||||
StyleClass="box-value"
|
|
||||||
ReturnType="Go"
|
|
||||||
ReturnCommand="{Binding ContinueCommand}"
|
|
||||||
AutomationId="EmailAddressEntry"
|
|
||||||
>
|
|
||||||
<VisualStateManager.VisualStateGroups>
|
|
||||||
<VisualStateGroup x:Name="CommonStates">
|
|
||||||
<VisualState x:Name="Disabled">
|
|
||||||
<VisualState.Setters>
|
|
||||||
<Setter Property="TextColor" Value="{DynamicResource MutedColor}" />
|
|
||||||
</VisualState.Setters>
|
|
||||||
</VisualState>
|
|
||||||
</VisualStateGroup>
|
|
||||||
</VisualStateManager.VisualStateGroups>
|
|
||||||
</Entry>
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Margin="0, 6, 0 ,0">
|
|
||||||
<StackLayout.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer
|
|
||||||
Command="{Binding ShowEnvironmentPickerCommand}" />
|
|
||||||
</StackLayout.GestureRecognizers>
|
|
||||||
<Label
|
|
||||||
Text="{Binding RegionText}"
|
|
||||||
FontSize="13"
|
|
||||||
TextColor="{DynamicResource MutedColor}"
|
|
||||||
VerticalOptions="Center"
|
|
||||||
VerticalTextAlignment="Center"/>
|
|
||||||
<controls:IconLabel
|
|
||||||
Text="{Binding SelectedEnvironmentName}"
|
|
||||||
FontSize="13"
|
|
||||||
TextColor="{DynamicResource PrimaryColor}"
|
|
||||||
VerticalOptions="Center"
|
|
||||||
VerticalTextAlignment="Center"
|
|
||||||
AutomationId="RegionSelectorDropdown"/>
|
|
||||||
</StackLayout>
|
|
||||||
<StackLayout
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Margin="0, 20, 0 ,0">
|
|
||||||
<StackLayout.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer
|
|
||||||
Command="{Binding RememberEmailCommand}" />
|
|
||||||
</StackLayout.GestureRecognizers>
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n RememberMe}"
|
|
||||||
StyleClass="text-sm"
|
|
||||||
HorizontalOptions="FillAndExpand"
|
|
||||||
VerticalOptions="Center"
|
|
||||||
VerticalTextAlignment="Center"
|
|
||||||
/>
|
|
||||||
<Switch
|
|
||||||
Scale="0.8"
|
|
||||||
IsToggled="{Binding RememberEmail}"
|
|
||||||
VerticalOptions="Center"
|
|
||||||
AutomationId="RememberMeSwitch"
|
|
||||||
/>
|
|
||||||
</StackLayout>
|
|
||||||
</StackLayout>
|
|
||||||
<Button Text="{u:I18n Continue}"
|
|
||||||
StyleClass="btn-primary"
|
|
||||||
IsEnabled="{Binding CanContinue}"
|
|
||||||
Command="{Binding ContinueCommand}"
|
|
||||||
AutomationId="ContinueButton"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Label FormattedText="{Binding CreateAccountText}"
|
|
||||||
Margin="0, 10"
|
|
||||||
StyleClass="box-footer-label"
|
|
||||||
AutomationId="CreateAccountLabel">
|
|
||||||
<Label.GestureRecognizers>
|
|
||||||
<TapGestureRecognizer Command="{Binding CreateAccountCommand}" />
|
|
||||||
</Label.GestureRecognizers>
|
|
||||||
</Label>
|
|
||||||
</StackLayout>
|
|
||||||
</ResourceDictionary>
|
|
||||||
</ContentPage.Resources>
|
|
||||||
|
|
||||||
<AbsoluteLayout
|
|
||||||
x:Name="_absLayout"
|
|
||||||
VerticalOptions="FillAndExpand"
|
|
||||||
HorizontalOptions="FillAndExpand">
|
|
||||||
<ContentView
|
|
||||||
x:Name="_mainContent"
|
|
||||||
AbsoluteLayout.LayoutFlags="All"
|
|
||||||
AbsoluteLayout.LayoutBounds="0, 0, 1, 1">
|
|
||||||
</ContentView>
|
|
||||||
|
|
||||||
<controls:AccountSwitchingOverlayView
|
|
||||||
x:Name="_accountListOverlay"
|
|
||||||
AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
|
|
||||||
AbsoluteLayout.LayoutFlags="All"
|
|
||||||
MainPage="{Binding Source={x:Reference _page}}"
|
|
||||||
BindingContext="{Binding AccountSwitchingOverlayViewModel}"/>
|
|
||||||
</AbsoluteLayout>
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
using Xamarin.Forms.PlatformConfiguration;
|
|
||||||
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class BaseContentPage : ContentPage
|
|
||||||
{
|
|
||||||
private IStateService _stateService;
|
|
||||||
private IDeviceActionService _deviceActionService;
|
|
||||||
|
|
||||||
protected int ShowModalAnimationDelay = 400;
|
|
||||||
protected int ShowPageAnimationDelay = 100;
|
|
||||||
|
|
||||||
public BaseContentPage()
|
|
||||||
{
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
On<iOS>().SetUseSafeArea(true);
|
|
||||||
On<iOS>().SetModalPresentationStyle(UIModalPresentationStyle.FullScreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime? LastPageAction { get; set; }
|
|
||||||
|
|
||||||
public bool IsThemeDirty { get; set; }
|
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
|
||||||
{
|
|
||||||
base.OnAppearing();
|
|
||||||
|
|
||||||
if (IsThemeDirty)
|
|
||||||
{
|
|
||||||
UpdateOnThemeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
await SaveActivityAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DoOnce(Action action = null, int milliseconds = 1000)
|
|
||||||
{
|
|
||||||
if (LastPageAction.HasValue && (DateTime.UtcNow - LastPageAction.Value).TotalMilliseconds < milliseconds)
|
|
||||||
{
|
|
||||||
// Last action occurred recently.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LastPageAction = DateTime.UtcNow;
|
|
||||||
action?.Invoke();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Task UpdateOnThemeChanged()
|
|
||||||
{
|
|
||||||
IsThemeDirty = false;
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void SetActivityIndicator(ContentView targetView = null)
|
|
||||||
{
|
|
||||||
var indicator = new ActivityIndicator
|
|
||||||
{
|
|
||||||
IsRunning = true,
|
|
||||||
VerticalOptions = LayoutOptions.CenterAndExpand,
|
|
||||||
HorizontalOptions = LayoutOptions.Center,
|
|
||||||
Color = ThemeManager.GetResourceColor("PrimaryColor"),
|
|
||||||
};
|
|
||||||
if (targetView != null)
|
|
||||||
{
|
|
||||||
targetView.Content = indicator;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Content = indicator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task LoadOnAppearedAsync(View sourceView, bool fromModal, Func<Task> workFunction,
|
|
||||||
ContentView targetView = null)
|
|
||||||
{
|
|
||||||
async Task DoWorkAsync()
|
|
||||||
{
|
|
||||||
await workFunction.Invoke();
|
|
||||||
if (sourceView != null)
|
|
||||||
{
|
|
||||||
if (targetView != null)
|
|
||||||
{
|
|
||||||
targetView.Content = sourceView;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Content = sourceView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Device.RuntimePlatform == Device.iOS)
|
|
||||||
{
|
|
||||||
await DoWorkAsync();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(fromModal ? ShowModalAnimationDelay : ShowPageAnimationDelay);
|
|
||||||
Device.BeginInvokeOnMainThread(async () => await DoWorkAsync());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void RequestFocus(InputView input)
|
|
||||||
{
|
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(ShowModalAnimationDelay);
|
|
||||||
Device.BeginInvokeOnMainThread(() => input.Focus());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<bool> ShowAccountSwitcherAsync()
|
|
||||||
{
|
|
||||||
return await _stateService.GetActiveUserIdAsync() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<AvatarImageSource> GetAvatarImageSourceAsync(bool useCurrentActiveAccount = true)
|
|
||||||
{
|
|
||||||
if (useCurrentActiveAccount)
|
|
||||||
{
|
|
||||||
var user = await _stateService.GetActiveUserCustomDataAsync(a => (a?.Profile?.UserId, a?.Profile?.Name, a?.Profile?.Email, a?.Profile?.AvatarColor));
|
|
||||||
return new AvatarImageSource(user.UserId, user.Name, user.Email, user.AvatarColor);
|
|
||||||
}
|
|
||||||
return new AvatarImageSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetServices()
|
|
||||||
{
|
|
||||||
if (_stateService == null)
|
|
||||||
{
|
|
||||||
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
|
|
||||||
}
|
|
||||||
if (_deviceActionService == null)
|
|
||||||
{
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveActivityAsync()
|
|
||||||
{
|
|
||||||
SetServices();
|
|
||||||
if (await _stateService.GetActiveUserIdAsync() == null)
|
|
||||||
{
|
|
||||||
// Fresh install and/or all users logged out won't have an active user, skip saving last active time
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _stateService.SetLastActiveTimeAsync(_deviceActionService.GetActiveTime());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using Bit.App.Abstractions;
|
|
||||||
using Bit.App.Controls;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Exceptions;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.CommunityToolkit.ObjectModel;
|
|
||||||
using Xamarin.Essentials;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public abstract class BaseViewModel : ExtendedViewModel
|
|
||||||
{
|
|
||||||
private string _pageTitle = string.Empty;
|
|
||||||
private AvatarImageSource _avatar;
|
|
||||||
private LazyResolve<IDeviceActionService> _deviceActionService = new LazyResolve<IDeviceActionService>();
|
|
||||||
private LazyResolve<IPlatformUtilsService> _platformUtilsService = new LazyResolve<IPlatformUtilsService>();
|
|
||||||
private LazyResolve<ILogger> _logger = new LazyResolve<ILogger>();
|
|
||||||
|
|
||||||
public string PageTitle
|
|
||||||
{
|
|
||||||
get => _pageTitle;
|
|
||||||
set => SetProperty(ref _pageTitle, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvatarImageSource AvatarImageSource
|
|
||||||
{
|
|
||||||
get => _avatar ?? new AvatarImageSource();
|
|
||||||
set => SetProperty(ref _avatar, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContentPage Page { get; set; }
|
|
||||||
|
|
||||||
protected void HandleException(Exception ex, string message = null)
|
|
||||||
{
|
|
||||||
if (ex is ApiException apiException && apiException.Error != null)
|
|
||||||
{
|
|
||||||
message = apiException.Error.GetSingleMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
Xamarin.Essentials.MainThread.InvokeOnMainThreadAsync(async () =>
|
|
||||||
{
|
|
||||||
await _deviceActionService.Value.HideLoadingAsync();
|
|
||||||
await _platformUtilsService.Value.ShowDialogAsync(message ?? AppResources.GenericErrorMessage);
|
|
||||||
}).FireAndForget();
|
|
||||||
_logger.Value.Exception(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AsyncCommand CreateDefaultAsyncCommnad(Func<Task> execute, Func<object, bool> canExecute = null)
|
|
||||||
{
|
|
||||||
return new AsyncCommand(execute,
|
|
||||||
canExecute,
|
|
||||||
ex => HandleException(ex),
|
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async Task<bool> HasConnectivityAsync()
|
|
||||||
{
|
|
||||||
if (Connectivity.NetworkAccess == NetworkAccess.None)
|
|
||||||
{
|
|
||||||
await _platformUtilsService.Value.ShowDialogAsync(
|
|
||||||
AppResources.InternetConnectionRequiredMessage,
|
|
||||||
AppResources.InternetConnectionRequiredTitle);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System.Windows.Input;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public partial class AutofillSettingsPageViewModel
|
|
||||||
{
|
|
||||||
public bool SupportsiOSAutofill => Device.RuntimePlatform == Device.iOS && _deviceActionService.SupportsAutofillServices();
|
|
||||||
|
|
||||||
public ICommand GoToPasswordAutofillCommand { get; private set; }
|
|
||||||
public ICommand GoToAppExtensionCommand { get; private set; }
|
|
||||||
|
|
||||||
private void InitIOSCommands()
|
|
||||||
{
|
|
||||||
GoToPasswordAutofillCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new AutofillPage())));
|
|
||||||
GoToAppExtensionCommand = CreateDefaultAsyncCommnad(() => Page.Navigation.PushModalAsync(new NavigationPage(new ExtensionPage())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<pages:BaseContentPage
|
|
||||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
|
||||||
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
|
|
||||||
x:Class="Bit.App.Pages.LoginPasswordlessRequestsListPage"
|
|
||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
|
||||||
x:DataType="pages:LoginPasswordlessRequestsListViewModel"
|
|
||||||
xmlns:models="clr-namespace:Bit.Core.Models.Response;assembly=BitwardenCore"
|
|
||||||
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
|
|
||||||
xmlns:controls="clr-namespace:Bit.App.Controls"
|
|
||||||
xmlns:u="clr-namespace:Bit.App.Utilities"
|
|
||||||
Title="{Binding PageTitle}">
|
|
||||||
|
|
||||||
<ContentPage.BindingContext>
|
|
||||||
<pages:LoginPasswordlessRequestsListViewModel />
|
|
||||||
</ContentPage.BindingContext>
|
|
||||||
|
|
||||||
<ContentPage.ToolbarItems>
|
|
||||||
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
|
|
||||||
</ContentPage.ToolbarItems>
|
|
||||||
|
|
||||||
<ContentPage.Resources>
|
|
||||||
<ResourceDictionary>
|
|
||||||
<u:DateTimeConverter x:Key="dateTime" />
|
|
||||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
|
||||||
<xct:ItemSelectedEventArgsConverter x:Key="ItemSelectedEventArgsConverter" />
|
|
||||||
<controls:SelectionChangedEventArgsConverter x:Key="SelectionChangedEventArgsConverter" />
|
|
||||||
<DataTemplate
|
|
||||||
x:Key="loginRequestTemplate"
|
|
||||||
x:DataType="models:PasswordlessLoginResponse">
|
|
||||||
<Grid
|
|
||||||
Padding="10, 0"
|
|
||||||
RowSpacing="0"
|
|
||||||
RowDefinitions="*, Auto, *, 10"
|
|
||||||
ColumnDefinitions="*, *"
|
|
||||||
AutomationId="LoginRequestCell">
|
|
||||||
<Label
|
|
||||||
Text="{u:I18n FingerprintPhrase}"
|
|
||||||
FontSize="Small"
|
|
||||||
Padding="0, 10, 0 ,0"
|
|
||||||
FontAttributes="Bold"/>
|
|
||||||
<controls:MonoLabel
|
|
||||||
FormattedText="{Binding FingerprintPhrase}"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
FontSize="Small"
|
|
||||||
Padding="0, 5, 0, 10"
|
|
||||||
VerticalTextAlignment="Center"
|
|
||||||
TextColor="{DynamicResource FingerprintPhrase}"
|
|
||||||
AutomationId="FingerprintPhraseLabel" />
|
|
||||||
<Label
|
|
||||||
Grid.Row="2"
|
|
||||||
HorizontalOptions="Start"
|
|
||||||
HorizontalTextAlignment="Start"
|
|
||||||
Text="{Binding RequestDeviceType}"
|
|
||||||
StyleClass="list-header-sub"
|
|
||||||
AutomationId="RequestDeviceLabel" />
|
|
||||||
<Label
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalOptions="End"
|
|
||||||
HorizontalTextAlignment="End"
|
|
||||||
Text="{Binding CreationDate, Converter={StaticResource dateTime}}"
|
|
||||||
StyleClass="list-header-sub"
|
|
||||||
AutomationId="RequestDateLabel" />
|
|
||||||
<BoxView
|
|
||||||
StyleClass="list-section-separator-top, list-section-separator-top-platform"
|
|
||||||
VerticalOptions="End"
|
|
||||||
Grid.Row="3"
|
|
||||||
Grid.ColumnSpan="2"/>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
|
|
||||||
<StackLayout
|
|
||||||
x:Key="mainLayout"
|
|
||||||
x:Name="_mainLayout"
|
|
||||||
Padding="0, 10">
|
|
||||||
<RefreshView
|
|
||||||
IsRefreshing="{Binding IsRefreshing}"
|
|
||||||
Command="{Binding RefreshCommand}"
|
|
||||||
VerticalOptions="FillAndExpand"
|
|
||||||
BackgroundColor="{DynamicResource BackgroundColor}">
|
|
||||||
<StackLayout>
|
|
||||||
<Image
|
|
||||||
x:Name="_emptyPlaceholder"
|
|
||||||
Source="empty_login_requests"
|
|
||||||
HorizontalOptions="Center"
|
|
||||||
WidthRequest="160"
|
|
||||||
HeightRequest="160"
|
|
||||||
Margin="0,70,0,0"
|
|
||||||
IsVisible="{Binding HasLoginRequests, Converter={StaticResource inverseBool}}"
|
|
||||||
AutomationProperties.IsInAccessibleTree="True"
|
|
||||||
AutomationProperties.Name="{u:I18n NoPendingRequests}" />
|
|
||||||
<controls:CustomLabel
|
|
||||||
StyleClass="box-label-regular"
|
|
||||||
Text="{u:I18n NoPendingRequests}"
|
|
||||||
FontAttributes="{OnPlatform iOS=Bold}"
|
|
||||||
FontWeight="500"
|
|
||||||
HorizontalTextAlignment="Center"
|
|
||||||
Margin="14,10,14,0"/>
|
|
||||||
<controls:ExtendedCollectionView
|
|
||||||
ItemsSource="{Binding LoginRequests}"
|
|
||||||
ItemTemplate="{StaticResource loginRequestTemplate}"
|
|
||||||
SelectionMode="Single"
|
|
||||||
IsVisible="{Binding HasLoginRequests}"
|
|
||||||
ExtraDataForLogging="Login requests page" >
|
|
||||||
<controls:ExtendedCollectionView.Behaviors>
|
|
||||||
<xct:EventToCommandBehavior
|
|
||||||
EventName="SelectionChanged"
|
|
||||||
Command="{Binding AnswerRequestCommand}"
|
|
||||||
EventArgsConverter="{StaticResource SelectionChangedEventArgsConverter}" />
|
|
||||||
</controls:ExtendedCollectionView.Behaviors>
|
|
||||||
</controls:ExtendedCollectionView>
|
|
||||||
</StackLayout>
|
|
||||||
</RefreshView>
|
|
||||||
<controls:IconLabelButton
|
|
||||||
VerticalOptions="End"
|
|
||||||
Margin="10,0"
|
|
||||||
Icon="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
|
|
||||||
Label="{u:I18n DeclineAllRequests}"
|
|
||||||
ButtonCommand="{Binding DeclineAllRequestsCommand}"
|
|
||||||
IsVisible="{Binding HasLoginRequests}"
|
|
||||||
AutomationId="DeleteAllRequestsButton" />
|
|
||||||
</StackLayout>
|
|
||||||
</ResourceDictionary>
|
|
||||||
</ContentPage.Resources>
|
|
||||||
|
|
||||||
<ContentView
|
|
||||||
x:Name="_mainContent">
|
|
||||||
</ContentView>
|
|
||||||
|
|
||||||
</pages:BaseContentPage>
|
|
||||||
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Bit.App.Resources;
|
|
||||||
using Bit.App.Utilities;
|
|
||||||
using Bit.Core.Abstractions;
|
|
||||||
using Bit.Core.Models.View;
|
|
||||||
using Bit.Core.Utilities;
|
|
||||||
using Xamarin.CommunityToolkit.ObjectModel;
|
|
||||||
using Xamarin.Essentials;
|
|
||||||
using Xamarin.Forms;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
|
||||||
{
|
|
||||||
public class GroupingsPageTOTPListItem : ExtendedViewModel, IGroupingsPageListItem
|
|
||||||
{
|
|
||||||
private readonly LazyResolve<ILogger> _logger = new LazyResolve<ILogger>("logger");
|
|
||||||
private readonly ITotpService _totpService;
|
|
||||||
private readonly IPlatformUtilsService _platformUtilsService;
|
|
||||||
private readonly IClipboardService _clipboardService;
|
|
||||||
private CipherView _cipher;
|
|
||||||
|
|
||||||
private bool _websiteIconsEnabled;
|
|
||||||
private string _iconImageSource = string.Empty;
|
|
||||||
|
|
||||||
private double _progress;
|
|
||||||
private string _totpSec;
|
|
||||||
private string _totpCodeFormatted;
|
|
||||||
private TotpHelper _totpTickHelper;
|
|
||||||
|
|
||||||
|
|
||||||
public GroupingsPageTOTPListItem(CipherView cipherView, bool websiteIconsEnabled)
|
|
||||||
{
|
|
||||||
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
|
||||||
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
|
||||||
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
|
|
||||||
|
|
||||||
Cipher = cipherView;
|
|
||||||
WebsiteIconsEnabled = websiteIconsEnabled;
|
|
||||||
CopyCommand = new AsyncCommand(CopyToClipboardAsync,
|
|
||||||
onException: ex => _logger.Value.Exception(ex),
|
|
||||||
allowsMultipleExecutions: false);
|
|
||||||
_totpTickHelper = new TotpHelper(cipherView);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsyncCommand CopyCommand { get; set; }
|
|
||||||
|
|
||||||
public CipherView Cipher
|
|
||||||
{
|
|
||||||
get => _cipher;
|
|
||||||
set => SetProperty(ref _cipher, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TotpCodeFormatted
|
|
||||||
{
|
|
||||||
get => _totpCodeFormatted;
|
|
||||||
set => SetProperty(ref _totpCodeFormatted, value,
|
|
||||||
additionalPropertyNames: new string[]
|
|
||||||
{
|
|
||||||
nameof(TotpCodeFormattedStart),
|
|
||||||
nameof(TotpCodeFormattedEnd),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TotpSec
|
|
||||||
{
|
|
||||||
get => _totpSec;
|
|
||||||
set => SetProperty(ref _totpSec, value);
|
|
||||||
}
|
|
||||||
public double Progress
|
|
||||||
{
|
|
||||||
get => _progress;
|
|
||||||
set => SetProperty(ref _progress, value);
|
|
||||||
}
|
|
||||||
public bool WebsiteIconsEnabled
|
|
||||||
{
|
|
||||||
get => _websiteIconsEnabled;
|
|
||||||
set => SetProperty(ref _websiteIconsEnabled, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowIconImage
|
|
||||||
{
|
|
||||||
get => WebsiteIconsEnabled
|
|
||||||
&& !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
|
|
||||||
&& IconImageSource != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string IconImageSource
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_iconImageSource == string.Empty) // default value since icon source can return null
|
|
||||||
{
|
|
||||||
_iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
|
|
||||||
}
|
|
||||||
return _iconImageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TotpCodeFormattedStart => TotpCodeFormatted?.Split(' ')[0];
|
|
||||||
|
|
||||||
public string TotpCodeFormattedEnd => TotpCodeFormatted?.Split(' ')[1];
|
|
||||||
|
|
||||||
public async Task CopyToClipboardAsync()
|
|
||||||
{
|
|
||||||
await _clipboardService.CopyTextAsync(TotpCodeFormatted?.Replace(" ", string.Empty));
|
|
||||||
_platformUtilsService.ShowToast("info", null, string.Format(AppResources.ValueHasBeenCopied, AppResources.VerificationCodeTotp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task TotpTickAsync()
|
|
||||||
{
|
|
||||||
await _totpTickHelper.GenerateNewTotpValues();
|
|
||||||
MainThread.BeginInvokeOnMainThread(() =>
|
|
||||||
{
|
|
||||||
TotpSec = _totpTickHelper.TotpSec;
|
|
||||||
Progress = _totpTickHelper.Progress;
|
|
||||||
TotpCodeFormatted = _totpTickHelper.TotpCodeFormatted;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ using Android.Views;
|
|||||||
using System;
|
using System;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.Droid.Utilities;
|
using Bit.App.Droid.Utilities;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@@ -10,8 +10,13 @@ using Android.Runtime;
|
|||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Bit.App.Resources;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core;
|
using Bit.Core;
|
||||||
|
using Application = Android.App.Application;
|
||||||
|
using View = Android.Views.View;
|
||||||
|
using Resource = Bit.Core.Resource;
|
||||||
|
using Point = Android.Graphics.Point;
|
||||||
|
using Rect = Android.Graphics.Rect;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
@@ -705,7 +710,7 @@ namespace Bit.Droid.Accessibility
|
|||||||
public static LinearLayout GetOverlayView(Context context)
|
public static LinearLayout GetOverlayView(Context context)
|
||||||
{
|
{
|
||||||
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
var inflater = (LayoutInflater)context.GetSystemService(Context.LayoutInflaterService);
|
||||||
var view = (LinearLayout)inflater.Inflate(Resource.Layout.autofill_listitem, null);
|
var view = (LinearLayout)inflater.Inflate(Bit.Core.Resource.Layout.autofill_listitem, null);
|
||||||
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
var text1 = (TextView)view.FindViewById(Resource.Id.text1);
|
||||||
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
var text2 = (TextView)view.FindViewById(Resource.Id.text2);
|
||||||
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
var icon = (ImageView)view.FindViewById(Resource.Id.icon);
|
||||||
@@ -9,9 +9,10 @@ using Android.Runtime;
|
|||||||
using Android.Views;
|
using Android.Views;
|
||||||
using Android.Views.Accessibility;
|
using Android.Views.Accessibility;
|
||||||
using Android.Widget;
|
using Android.Widget;
|
||||||
using Bit.App.Resources;
|
using Bit.Core.Resources.Localization;
|
||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using View = Android.Views.View;
|
||||||
|
|
||||||
namespace Bit.Droid.Accessibility
|
namespace Bit.Droid.Accessibility
|
||||||
{
|
{
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user