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

Compare commits

..

62 Commits

Author SHA1 Message Date
Federico Maccaroni
ea28fd462d Fixed flickering on iOS while loading collections for the collection crash hotfix 2022-03-18 15:59:19 -03:00
Federico Maccaroni
14b6ccca6d Fix iOS 15.4 crash from empty list to adding an item by awaiting after every header add; also added that on Settings just in case there is another crash scenario 2022-03-17 17:55:33 -03:00
github-actions[bot]
4202a90674 Bumped version to 2.16.4 (#1846)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
(cherry picked from commit c47aad0412)
2022-03-16 12:50:59 -07:00
Federico Maccaroni
ad55ba232f Removed grouping from Settings to fix a crash on iOS 15.4 2022-03-15 11:21:20 -03:00
Micaiah Martin
1f8620dc17 Moved to new Google Service Account (#1789)
(cherry picked from commit a9be659e27)
2022-03-14 12:52:14 -07:00
Micaiah Martin
a4bc46f408 Moved to new Google Service Account (#1788)
(cherry picked from commit 39596d7533)
2022-03-14 12:52:10 -07:00
Daniel James Smith
62f1522af3 Bump target framework to netcoreapp3.1 (#1817)
Co-authored-by: Micaiah Martin <77340197+mimartin12@users.noreply.github.com>
(cherry picked from commit 2076c11cbd)
2022-03-14 12:28:49 -07:00
Micaiah Martin
3d0a405d7d Renewed certificates and profiles (#1823)
(cherry picked from commit a33232dec0)
2022-03-14 12:07:38 -07:00
Federico Maccaroni
bb18e40d00 Fix #1745 crash on scroll of grouped collection view on iOS 15.4 beta 2022-03-14 16:05:40 -03:00
github-actions[bot]
6305b4d292 Bumped version to 2.16.3 (#1843)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-03-14 12:01:32 -07:00
Joseph Flinn
3562e2bac6 Patch/release new build artifact name (#1778)
* Switching the iOS build artifact and release asset names

* disabling jobs/steps to test the new release asset name

* switching to download artifacts from rc

* testing the upload of the 'Bitwarden iOS' directory

* Build zip asset of the Bitwarden iOS asset

* trying a couple of different zip paths

* Final package test

* Re-enabling all of the jobs after testing

(cherry picked from commit 95581bd4d9)
2022-03-14 11:51:52 -07:00
Joseph Flinn
403f78ceca Update hotfix release branch name to hotfix-rc (#1834)
(cherry picked from commit bdd0ea007b)
2022-03-14 11:50:09 -07:00
Federico Maccaroni
e4e52a41e0 Merge branch 'master' into rc
* master:
  Build: Upload dSYMs to AppCenter (#1776)
  Fix for vault timeout not firing on resume (#1775)
2022-02-14 16:36:38 -03:00
Federico Maccaroni
4fb811ae87 Build: Upload dSYMs to AppCenter (#1776)
* Added dsym artifact to be uploaded alongside with the ipa o the build.yml

* Added dsym artifact to be uploaded alongside with the ipa o the build.yml

* Fixed build.yml dsym artifact

* Fix upload dsym build.yml

* Fix build.yml to check what gets exported and after this will become the adjustment for the dsym (disabling Android build for this test)

* Fix build.yml to copy all dsyms and artifact them (disabling Android build for this test)

* Fix build.yml to only copy all dsyms and ipa and artifact them (disabling Android build for this test)

* Added Appcenterr CLI and upload missing symbols for dSYM to the build

* Add secret to build workflow (#1771)

* Changed build.yml upload dsym command from upload-missing-symbols to upload-symbols

* Added restrictions for uploading iOS symbols to AppCenter on build.yml

Co-authored-by: Vince Grassia <593223+vgrassia@users.noreply.github.com>
2022-02-14 11:06:35 -08:00
Matt Portune
2e1de95461 Fix for vault timeout not firing on resume (#1775)
* fix for vault timeout not firing on resume

* call ResumedAsync with FireAndForget
2022-02-14 11:30:00 -05:00
Matt Portune
3127295444 Fix for vault timeout not firing on resume (#1775)
* fix for vault timeout not firing on resume

* call ResumedAsync with FireAndForget
2022-02-14 11:29:04 -05:00
Federico Maccaroni
52f1143ad7 Merge branch 'master' into rc
* master:
  [Icons] - BUG - Update groupings icon for collections (#1773)
  Autosync the updated translations (#1766)
  check email for null before authenticating (#1769)
  remove datepicker style workaround (#1768)
  Bump version to 2.16.2 (#1765)
  Improved code for periodic Autofocus on scan for better cancellation and task handlilng (#1764)
  Updated Sed expression for Android manifests (#1763)
  Bumped version to 2.16.1 (#1762)
  Add iOS Share Extension to our version bump automation (#1761)
  Bumped version to 2.16.0 (#1760)
  Improved Autofocus code on ScanPage for better cancellation and exception handling #1228 (#1759)
  [Help] Update links to new pattern (#1758)
  Client & Version headers (#1757)
  Autosync the updated translations (#1752)
  Fix delete account SSO with CME that the OTP parameter was being sent incorrectly to the server (#1751)
  [Icons] Fast follower changes (#1750)
  Removed punctuation on some string resources regarding send (#1747)

# Conflicts:
#	src/Android/Properties/AndroidManifest.xml
#	src/iOS.Autofill/Info.plist
#	src/iOS.Extension/Info.plist
#	src/iOS.ShareExtension/Info.plist
#	src/iOS/Info.plist
2022-02-14 10:12:23 -03:00
Vincent Salucci
615136be96 [Icons] - BUG - Update groupings icon for collections (#1773) 2022-02-12 12:27:37 +00:00
github-actions[bot]
e4230ac4f6 Autosync the updated translations (#1766)
Co-authored-by: github-actions <>
2022-02-11 22:47:48 +01:00
Jake Fink
15e9915da6 check email for null before authenticating (#1769)
* check email for null before authenticating

* add return after logging out and track error if email not found
2022-02-11 13:46:17 -05:00
Jake Fink
59ed76d956 remove datepicker style workaround (#1768) 2022-02-11 12:23:51 -05:00
github-actions[bot]
972755c725 Bump version to 2.16.2 (#1765)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-02-10 13:47:03 -07:00
Federico Maccaroni
92c40e2984 Improved code for periodic Autofocus on scan for better cancellation and task handlilng (#1764) 2022-02-10 13:03:02 -05:00
Micaiah Martin
56de47960d Updated Sed expression for Android manifests (#1763)
(cherry picked from commit 9eed421c67)
2022-02-10 08:43:31 -08:00
Micaiah Martin
9eed421c67 Updated Sed expression for Android manifests (#1763) 2022-02-10 09:42:57 -07:00
github-actions[bot]
9b17392e06 Bumped version to 2.16.1 (#1762)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
(cherry picked from commit 15db96b06c)
2022-02-10 08:21:09 -08:00
github-actions[bot]
15db96b06c Bumped version to 2.16.1 (#1762)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-02-10 08:19:02 -08:00
Joseph Flinn
54ccc1cbca Add iOS Share Extension to our version bump automation (#1761) 2022-02-10 07:54:43 -08:00
github-actions[bot]
6bed326f28 Bumped version to 2.16.0 (#1760)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
(cherry picked from commit ee69364b1d)
2022-02-10 06:48:26 -08:00
github-actions[bot]
ee69364b1d Bumped version to 2.16.0 (#1760)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-02-10 06:46:19 -08:00
Federico Maccaroni
76f1057951 Improved Autofocus code on ScanPage for better cancellation and exception handling #1228 (#1759) 2022-02-09 14:22:04 -03:00
Vincent Salucci
3491c1aaeb [Help] Update links to new pattern (#1758) 2022-02-08 17:42:53 -06:00
Oscar Hinton
427ff09af0 Client & Version headers (#1757) 2022-02-08 17:43:40 +01:00
Federico Maccaroni
6453836866 Fix delete account SSO with CME that the OTP parameter was being sent incorrectly to the server (#1751) 2022-02-04 12:13:50 -03:00
github-actions[bot]
10fafaf8c8 Autosync the updated translations (#1752)
Co-authored-by: github-actions <>
2022-02-04 12:56:49 +01:00
Federico Maccaroni
31cdf401f1 Fix delete account SSO with CME that the OTP parameter was being sent incorrectly to the server (#1751) 2022-02-03 17:46:45 -03:00
Vincent Salucci
0068674bac [Icons] Fast follower changes (#1750) 2022-02-03 10:37:21 -06:00
Vincent Salucci
4373cee636 [Icons] Fast follower changes (#1750) 2022-02-03 10:34:20 -06:00
Federico Maccaroni
63b27f4e6d Removed punctuation on some string resources regarding send (#1747) 2022-02-02 16:07:58 -03:00
Jake Fink
fba5ecf304 Set background of biometricCell from theme (#1744) 2022-01-31 22:00:05 +00:00
Federico Maccaroni
a183861b87 Cleared About information about push registration, just left it in DEBUG mode (#1742) 2022-01-31 14:48:35 -03:00
Federico Maccaroni
d0ffb108b1 Cleared Console.WriteLine for iOS push notifications issue (#1739) 2022-01-31 11:12:24 -03:00
github-actions[bot]
c0c893fd59 Autosync the updated translations (#1734)
Co-authored-by: github-actions <>
2022-01-28 11:08:29 +01:00
Oscar Hinton
5f29fc8f89 Update FA icons on LockPasswordViewController (#1729)
Co-authored-by: Jacob Fink <jfink@bitwarden.com>
2022-01-27 18:13:23 +01:00
Federico Maccaroni
f8a7eb4c94 Add Share app Extension on iOS for Send (re-PR) (#1660)
* WIP Add Share app extension on iOS for Send

* Added Share app extension on iOS for Send and some code fixes as well

* Updated iOS csprojs configs to linkskip the new extension project and also added AdHoc and AppStore configurations to iOS.ShareExtension.csproj

* Code clean up and transformed bundle resources into links to the already used pngs of the main iOS project on ShareExtension

* Updated build.yml to include provisioning profile for iOS Share extension

* Adding in the missing provisioning profile

* Removed .DS_Store from the iOS.ShareExtension csproj Resources

* switching out the share extension profile

* Added Share extension provisioning profile configuration on export options app store for github and also removed custom info.plist config for localhost which is not necessary

* Moved property so that it's grouped with the full ones

* Added AppCenter Crashes package to Core and updated FireAndForget Task Extension

* Updated bundle reference of FontAwesome.ttf to bwi-font.ttf in order for it to compile on ShareExtension

Co-authored-by: Joseph Flinn <joseph.s.flinn@gmail.com>
Co-authored-by: Álison Fernandes <vvolkgang@users.noreply.github.com>
2022-01-25 17:41:56 -03:00
Federico Maccaroni
ef6184a05b Added hide loading after requesting OTP on verification code (#1732) 2022-01-25 17:07:10 -03:00
Federico Maccaroni
37f4439892 Added Logs for PN registration checks (#1731) 2022-01-25 16:33:33 -03:00
Jake Fink
f1ccbbc105 Expand Settings TimePicker tap recognition to entire row (#1714)
* move timepicker to separate DataTemplate
- activate timepicker when selecting row

* null check on TimePicker
2022-01-24 15:21:52 -05:00
Federico Maccaroni
74e90da662 Improve Theming (#1707)
* Improved theming logic and performance, also fixed some issues regarding changing the theme after vault timeout and fixed theme applying on password generator/history

* Removed messenger from theme update, and now the navigation stack is traversed and each IThemeDirtablePage gets theme updated

* Improved code on update theme on pages
2022-01-24 17:20:48 -03:00
Federico Maccaroni
939db8ebe0 Fix icon update on verify code view (#1728) 2022-01-24 14:19:30 -03:00
Federico Maccaroni
4e7ceaf5b5 Account Deletion on SSO with CME (#1721)
* WIP Added Verification Code page and a verification flow helper to coordinate things

* Improved Verification Code page verification flow helper and fix some issues, also added flag ApiService to choose whether to logout on Unanuthorized

* Improved Verification Code page UI/UX verification flow helper and fix some issues and made some cleanups

* Fix spelling
2022-01-24 13:25:46 -03:00
Federico Maccaroni
5a6aec51f3 Fix Progress dialog crash on tombstoning (#1682)
* Changed ProgressDialog because deprecated and improved the dismissal of the dialog in order for it not to crash the app on certain situations

* Removed android version check given that our minimum is greater that the check
2022-01-21 23:14:48 +00:00
github-actions[bot]
137c762e40 Autosync the updated translations (#1724)
Co-authored-by: github-actions <>
2022-01-21 11:53:41 +01:00
Oscar Hinton
3f1674c1f1 Icon Updates (#1541) 2022-01-21 10:31:03 +01:00
Jake Fink
52024109f7 Check for disable save prompt option before sending fill request in Android Autofill (#1722)
* Check for disable save prompt option before sending fill request
- ignore save request payload if true

* Add exception handling to Autofill Service

* move System reference outside of FDROID
2022-01-20 09:51:42 -05:00
Jake Fink
6f3999016f Supress lock and logout when showing fileswitcher on Android (#1626)
* Supress lock and logout when showing fileswitcher on Android

* convert suppress bool to delay long
- move HandleVaultTimeoutAsync to vaultTimeoutService
2022-01-19 09:09:30 -05:00
Federico Maccaroni
2791d4b8ec Fixes for iOS push notifications (#1708)
* WIP Fixes for iOS push notifications

* WIP Fixes for iOS push notifications, fix missed implementation on android

* Fix some issues on the push notifications, changed to Debug Console.WriteLine, and added update on entitlements on the build.yml
2022-01-18 11:52:08 -03:00
Indranil012
42403210a0 Added kiwi Browser "Dev" package name for autofill support (#1694)
* Added Kiwi Browser Dev support
2022-01-17 22:10:33 +00:00
Vince Grassia
5e15a2f30e Update Version Bump action (#1717) 2022-01-12 16:07:01 -05:00
github-actions[bot]
c6547771a5 Autosync the updated translations (#1709)
Co-authored-by: github-actions <>
2022-01-07 13:51:27 +01:00
Federico Maccaroni
9fdcba386e Possible fix for iOS crash after long time idling (#1700) 2022-01-03 12:46:42 -03:00
github-actions[bot]
86397a6f1e Autosync the updated translations (#1705)
Co-authored-by: github-actions <>
2022-01-01 17:52:21 +01:00
252 changed files with 5273 additions and 1509 deletions

View File

@@ -12,6 +12,8 @@
<string>Dist: Autofill 2021</string>
<key>com.8bit.bitwarden.find-login-action-extension</key>
<string>Dist: Extension 2021</string>
<key>com.8bit.bitwarden.share-extension</key>
<string>Dist: Share Extension 2021</string>
</dict>
</dict>
</plist>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -43,7 +43,7 @@ jobs:
echo "::set-output name=rc_branch_exists::0"
fi
if [[ $(git ls-remote --heads origin hotfix) ]]; then
if [[ $(git ls-remote --heads origin hotfix-rc) ]]; then
echo "::set-output name=hotfix_branch_exists::1"
else
echo "::set-output name=hotfix_branch_exists::0"
@@ -182,9 +182,9 @@ jobs:
&& 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'
|| github.ref == 'refs/heads/hotfix-rc'
run: |
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/netcoreapp2.0/Publisher.dll"
PUBLISHER_PATH="$GITHUB_WORKSPACE/store/google/Publisher/bin/Release/netcoreapp3.1/Publisher.dll"
CREDS_PATH="$HOME/secrets/play_creds.json"
AAB_PATH="$GITHUB_WORKSPACE/com.x8bit.bitwarden.aab"
TRACK="internal"
@@ -366,6 +366,18 @@ jobs:
- name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
- name: Login to Azure - Prod Subscription
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a
with:
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
- name: Retrieve secrets
id: retrieve-secrets
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403
with:
keyvault: "bitwarden-prod-kv"
secrets: "appcenter-ios-token"
- name: Decrypt secrets
env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
@@ -382,6 +394,8 @@ jobs:
--output $HOME/secrets/dist_bitwarden.mobileprovision ./.github/secrets/dist_bitwarden.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output $HOME/secrets/dist_extension.mobileprovision ./.github/secrets/dist_extension.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$DECRYPT_FILE_PASSWORD" \
--output $HOME/secrets/dist_share_extension.mobileprovision ./.github/secrets/dist_share_extension.mobileprovision.gpg
shell: bash
- name: Increment version
@@ -395,6 +409,16 @@ jobs:
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.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
shell: bash
- name: Update Entitlements
run: |
echo "########################################"
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>/' ./src/iOS/Entitlements.plist
shell: bash
- name: Set up Keychain
@@ -419,6 +443,7 @@ jobs:
AUTOFILL_PROFILE_PATH=$HOME/secrets/dist_autofill.mobileprovision
BITWARDEN_PROFILE_PATH=$HOME/secrets/dist_bitwarden.mobileprovision
EXTENSION_PROFILE_PATH=$HOME/secrets/dist_extension.mobileprovision
SHARE_EXTENSION_PROFILE_PATH=$HOME/secrets/dist_share_extension.mobileprovision
PROFILES_DIR_PATH=$HOME/Library/MobileDevice/Provisioning\ Profiles
mkdir -p "$PROFILES_DIR_PATH"
@@ -431,6 +456,9 @@ jobs:
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"
shell: bash
- name: Restore packages
@@ -463,20 +491,55 @@ jobs:
-exportOptionsPlist $EXPORT_OPTIONS_PATH
shell: bash
- name: Upload App Store .ipa artifact
- name: Copy all dSYMs files to upload
run: |
ARCHIVE_DSYMS_PATH="$HOME/Library/Developer/Xcode/Archives/*/*.xcarchive/dSYMs"
EXPORT_PATH="./bitwarden-export"
cp -r $ARCHIVE_DSYMS_PATH $EXPORT_PATH
shell: bash
- name: Upload App Store .ipa & dSYMs artifacts
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.4
with:
name: Bitwarden.ipa
path: ./bitwarden-export/Bitwarden.ipa
name: Bitwarden iOS
path: |
./bitwarden-export/Bitwarden.ipa
./bitwarden-export/dSYMs/*.*
if-no-files-found: error
- name: Install AppCenter CLI
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'
uses: actions/setup-node@v2
with:
node-version: '14'
- run: npm install -g appcenter-cli
- name: Upload dSYMs to App Center
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:
APPCENTER_IOS_TOKEN: ${{ steps.retrieve-secrets.outputs.appcenter-ios-token }}
run: |
appcenter crashes upload-symbols -a kspearrin/bitwarden -s "./bitwarden-export/dSYMs" --token $APPCENTER_IOS_TOKEN
shell: bash
- name: Deploy to 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'
|| github.ref == 'refs/heads/hotfix-rc'
env:
APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
@@ -539,7 +602,7 @@ jobs:
if: |
(github.ref == 'refs/heads/master')
|| (github.ref == 'refs/heads/rc')
|| (github.ref == 'refs/heads/hotfix')
|| (github.ref == 'refs/heads/hotfix-rc')
env:
CLOC_STATUS: ${{ needs.cloc.result }}
ANDROID_STATUS: ${{ needs.android.result }}

View File

@@ -22,9 +22,9 @@ jobs:
steps:
- name: Branch check
run: |
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix" ]]; then
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
echo "==================================="
echo "[!] Can only release from the 'rc' or 'hotfix' branches"
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
echo "==================================="
exit 1
fi
@@ -35,7 +35,7 @@ jobs:
- name: Retrieve Mobile release version
id: retrieve-mobile-version
run: |
ver=$(sed -n -e '/android:versionName/ s/.*\= *//p' ./src/Android/Properties/AndroidManifest.xml | tr -d '"')
ver=$(sed -E -n '/^<manifest/s/^.*[ ]android:versionName="([^"]+)".*$/\1/p' ./src/Android/Properties/AndroidManifest.xml | tr -d '"')
echo "::set-output name=mobile_version::${ver}"
shell: bash
@@ -68,13 +68,16 @@ jobs:
workflow_conclusion: success
branch: ${{ steps.branch.outputs.branch-name }}
- name: Prep Bitwarden iOS release asset
run: zip -r Bitwarden\ iOS.zip Bitwarden\ iOS
- name: Create release
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 # v2.8.5
with:
artifacts: "./com.x8bit.bitwarden.aab/com.x8bit.bitwarden.aab,
./com.x8bit.bitwarden.apk/com.x8bit.bitwarden.apk,
./com.x8bit.bitwarden-fdroid.apk/com.x8bit.bitwarden-fdroid.apk,
./Bitwarden.ipa/Bitwarden.ipa"
./Bitwarden iOS.zip"
commit: ${{ github.sha }}
tag: v${{ steps.retrieve-mobile-version.outputs.mobile_version }}
name: Version ${{ steps.retrieve-mobile-version.outputs.mobile_version }}

View File

@@ -27,25 +27,31 @@ jobs:
ref: version_bump_${{ github.event.inputs.version_number }}
- name: Bump Version - Android XML
uses: bitwarden/gh-actions/version-bump@0c263b3963211ccaf5804313c3b3a0bcc52d4b19
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/Android/Properties/AndroidManifest.xml"
- name: Bump Version - iOS.Autofill
uses: bitwarden/gh-actions/version-bump@0c263b3963211ccaf5804313c3b3a0bcc52d4b19
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.Autofill/Info.plist"
- name: Bump Version - iOS.Extension
uses: bitwarden/gh-actions/version-bump@0c263b3963211ccaf5804313c3b3a0bcc52d4b19
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.Extension/Info.plist"
- name: Bump Version - iOS.ShareExtension
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS.ShareExtension/Info.plist"
- name: Bump Version - iOS
uses: bitwarden/gh-actions/version-bump@0c263b3963211ccaf5804313c3b3a0bcc52d4b19
uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945
with:
version: ${{ github.event.inputs.version_number }}
file_path: "./src/iOS/Info.plist"
@@ -78,6 +84,6 @@ jobs:
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
- [ ] Build/deploy pipeline (DevOps)
- [X] Other
## Objective
Automated version bump to ${{ github.event.inputs.version_number }}"
Automated version bump to ${{ github.event.inputs.version_number }}"

View File

@@ -38,12 +38,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS", "src\iOS\iOS.csproj",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Extension", "src\iOS.Extension\iOS.Extension.csproj", "{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "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}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Autofill", "src\iOS.Autofill\iOS.Autofill.csproj", "{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -325,35 +327,6 @@ Global
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhone.Build.0 = Release|iPhone
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{324BE76C-38FA-4F11-8BB1-95C7B3B1B545}.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
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -414,6 +387,65 @@ Global
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhone.Build.0 = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.AppStore|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.ActiveCfg = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhone.Build.0 = Debug|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|Any CPU.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.FDroid|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|Any CPU.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.ActiveCfg = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhone.Build.0 = Release|iPhone
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{F8C3F648-EA5A-4719-8005-85D1690B1655}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|Any CPU.Build.0 = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|Any CPU.Build.0 = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhone.Build.0 = AppStore|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|Any CPU.ActiveCfg = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.ActiveCfg = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Build.0 = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhone.Deploy.0 = Debug|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|Any CPU.Build.0 = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhone.Build.0 = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.FDroid|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|Any CPU.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.ActiveCfg = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhone.Build.0 = Release|iPhone
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -428,9 +460,10 @@ Global
{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}
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{4085B0A5-12A9-4993-B8B8-4ACE72E62E39} = {8904C536-C67D-420F-9971-51B26574C3AA}
{8AE548D9-A567-4E97-995E-93EC7DB0FDE0} = {8904C536-C67D-420F-9971-51B26574C3AA}
{F8C3F648-EA5A-4719-8005-85D1690B1655} = {D10CA4A9-F866-40E1-B658-F69051236C71}
{8A3ECD75-3EC8-4CB3-B3A2-A73A724C279A} = {D10CA4A9-F866-40E1-B658-F69051236C71}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7D436EA3-8B7E-45D2-8D14-0730BD2E0410}

View File

@@ -54,6 +54,7 @@ namespace Bit.Droid.Accessibility
// Rem. for "com.google.android.captiveportallogin": URL displayed in ActionBar subtitle without viewId.
new Browser("com.jamal2367.styx", "search"),
new Browser("com.kiwibrowser.browser", "url_bar"),
new Browser("com.kiwibrowser.browser.dev", "url_bar"),
new Browser("com.microsoft.emmx", "url_bar"),
new Browser("com.microsoft.emmx.beta", "url_bar"),
new Browser("com.microsoft.emmx.canary", "url_bar"),

View File

@@ -153,7 +153,7 @@
<Compile Include="Utilities\IntentExtensions.cs" />
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\FontAwesome.ttf" />
<AndroidAsset Include="Assets\bwi-font.ttf" />
<AndroidAsset Include="Assets\RobotoMono_Regular.ttf" />
<AndroidAsset Include="Assets\MaterialIcons_Regular.ttf" />
<None Include="8bit.keystore.enc" />
@@ -182,15 +182,16 @@
<AndroidResource Include="Resources\drawable\login.xml" />
<AndroidResource Include="Resources\drawable\logo.xml" />
<AndroidResource Include="Resources\drawable\logo_white.xml" />
<AndroidResource Include="Resources\drawable\paper_plane.xml" />
<AndroidResource Include="Resources\drawable\send.xml" />
<AndroidResource Include="Resources\drawable\pencil.xml" />
<AndroidResource Include="Resources\drawable\plus.xml" />
<AndroidResource Include="Resources\drawable\refresh.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" />

Binary file not shown.

Binary file not shown.

View File

@@ -73,6 +73,7 @@ namespace Bit.Droid.Autofill
"com.google.android.captiveportallogin",
"com.jamal2367.styx",
"com.kiwibrowser.browser",
"com.kiwibrowser.browser.dev",
"com.microsoft.emmx",
"com.microsoft.emmx.beta",
"com.microsoft.emmx.canary",
@@ -159,7 +160,7 @@ namespace Bit.Droid.Autofill
return new List<FilledItem>();
}
public static FillResponse BuildFillResponse(Parser parser, List<FilledItem> items, bool locked,
public static FillResponse.Builder CreateFillResponse(Parser parser, List<FilledItem> items, bool locked,
bool inlineAutofillEnabled, FillRequest fillRequest = null)
{
// Acquire inline presentation specs on Android 11+
@@ -210,9 +211,8 @@ namespace Bit.Droid.Autofill
}
responseBuilder.AddDataset(BuildVaultDataset(parser.ApplicationContext, parser.FieldCollection,
parser.Uri, locked, inlinePresentationSpecs));
AddSaveInfo(parser, fillRequest, responseBuilder, parser.FieldCollection);
responseBuilder.SetIgnoredIds(parser.FieldCollection.IgnoreAutofillIds.ToArray());
return responseBuilder.Build();
return responseBuilder;
}
public static Dataset BuildDataset(Context context, FieldCollection fields, FilledItem filledItem,

View File

@@ -9,6 +9,10 @@ using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
using System;
using System.Collections.Generic;
using System.Linq;
@@ -29,115 +33,138 @@ namespace Bit.Droid.Autofill
public async override void OnFillRequest(FillRequest request, CancellationSignal cancellationSignal,
FillCallback callback)
{
var structure = request.FillContexts?.LastOrDefault()?.Structure;
if (structure == null)
try
{
return;
}
var parser = new Parser(structure, ApplicationContext);
parser.Parse();
if (_storageService == null)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
}
var shouldAutofill = await parser.ShouldAutofillAsync(_storageService);
if (!shouldAutofill)
{
return;
}
var inlineAutofillEnabled = await _storageService.GetAsync<bool?>(Constants.InlineAutofillEnabledKey) ?? true;
if (_vaultTimeoutService == null)
{
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
}
List<FilledItem> items = null;
await _vaultTimeoutService.CheckVaultTimeoutAsync();
var locked = await _vaultTimeoutService.IsLockedAsync();
if (!locked)
{
if (_cipherService == null)
var structure = request.FillContexts?.LastOrDefault()?.Structure;
if (structure == null)
{
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
return;
}
items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService);
}
// build response
var response = AutofillHelpers.BuildFillResponse(parser, items, locked, inlineAutofillEnabled, request);
callback.OnSuccess(response);
var parser = new Parser(structure, ApplicationContext);
parser.Parse();
if (_storageService == null)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
}
var shouldAutofill = await parser.ShouldAutofillAsync(_storageService);
if (!shouldAutofill)
{
return;
}
var inlineAutofillEnabled = await _storageService.GetAsync<bool?>(Constants.InlineAutofillEnabledKey) ?? true;
if (_vaultTimeoutService == null)
{
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
}
List<FilledItem> items = null;
await _vaultTimeoutService.CheckVaultTimeoutAsync();
var locked = await _vaultTimeoutService.IsLockedAsync();
if (!locked)
{
if (_cipherService == null)
{
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
}
items = await AutofillHelpers.GetFillItemsAsync(parser, _cipherService);
}
// build response
var response = AutofillHelpers.CreateFillResponse(parser, items, locked, inlineAutofillEnabled, request);
var disableSavePrompt = await _storageService.GetAsync<bool?>(Constants.AutofillDisableSavePromptKey);
if (!disableSavePrompt.GetValueOrDefault())
{
AutofillHelpers.AddSaveInfo(parser, request, response, parser.FieldCollection);
}
callback.OnSuccess(response.Build());
}
catch (Exception e)
{
#if !FDROID
Crashes.TrackError(e);
#endif
}
}
public async override void OnSaveRequest(SaveRequest request, SaveCallback callback)
{
var structure = request.FillContexts?.LastOrDefault()?.Structure;
if (structure == null)
try
{
return;
}
if (_storageService == null)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
}
var disableSavePrompt = await _storageService.GetAsync<bool?>(Constants.AutofillDisableSavePromptKey);
if (disableSavePrompt.GetValueOrDefault())
{
return;
}
_policyService ??= ServiceContainer.Resolve<IPolicyService>("policyService");
var personalOwnershipPolicyApplies = await _policyService.PolicyAppliesToUser(PolicyType.PersonalOwnership);
if (personalOwnershipPolicyApplies)
{
return;
}
var parser = new Parser(structure, ApplicationContext);
parser.Parse();
var savedItem = parser.FieldCollection.GetSavedItem();
if (savedItem == null)
{
Toast.MakeText(this, "Unable to save this form.", ToastLength.Short).Show();
return;
}
var intent = new Intent(this, typeof(MainActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop);
intent.PutExtra("autofillFramework", true);
intent.PutExtra("autofillFrameworkSave", true);
intent.PutExtra("autofillFrameworkType", (int)savedItem.Type);
switch (savedItem.Type)
{
case CipherType.Login:
intent.PutExtra("autofillFrameworkName", parser.Uri
.Replace(Constants.AndroidAppProtocol, string.Empty)
.Replace("https://", string.Empty)
.Replace("http://", string.Empty));
intent.PutExtra("autofillFrameworkUri", parser.Uri);
intent.PutExtra("autofillFrameworkUsername", savedItem.Login.Username);
intent.PutExtra("autofillFrameworkPassword", savedItem.Login.Password);
break;
case CipherType.Card:
intent.PutExtra("autofillFrameworkCardName", savedItem.Card.Name);
intent.PutExtra("autofillFrameworkCardNumber", savedItem.Card.Number);
intent.PutExtra("autofillFrameworkCardExpMonth", savedItem.Card.ExpMonth);
intent.PutExtra("autofillFrameworkCardExpYear", savedItem.Card.ExpYear);
intent.PutExtra("autofillFrameworkCardCode", savedItem.Card.Code);
break;
default:
Toast.MakeText(this, "Unable to save this type of form.", ToastLength.Short).Show();
var structure = request.FillContexts?.LastOrDefault()?.Structure;
if (structure == null)
{
return;
}
if (_storageService == null)
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
}
var disableSavePrompt = await _storageService.GetAsync<bool?>(Constants.AutofillDisableSavePromptKey);
if (disableSavePrompt.GetValueOrDefault())
{
return;
}
_policyService ??= ServiceContainer.Resolve<IPolicyService>("policyService");
var personalOwnershipPolicyApplies = await _policyService.PolicyAppliesToUser(PolicyType.PersonalOwnership);
if (personalOwnershipPolicyApplies)
{
return;
}
var parser = new Parser(structure, ApplicationContext);
parser.Parse();
var savedItem = parser.FieldCollection.GetSavedItem();
if (savedItem == null)
{
Toast.MakeText(this, "Unable to save this form.", ToastLength.Short).Show();
return;
}
var intent = new Intent(this, typeof(MainActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTop);
intent.PutExtra("autofillFramework", true);
intent.PutExtra("autofillFrameworkSave", true);
intent.PutExtra("autofillFrameworkType", (int)savedItem.Type);
switch (savedItem.Type)
{
case CipherType.Login:
intent.PutExtra("autofillFrameworkName", parser.Uri
.Replace(Constants.AndroidAppProtocol, string.Empty)
.Replace("https://", string.Empty)
.Replace("http://", string.Empty));
intent.PutExtra("autofillFrameworkUri", parser.Uri);
intent.PutExtra("autofillFrameworkUsername", savedItem.Login.Username);
intent.PutExtra("autofillFrameworkPassword", savedItem.Login.Password);
break;
case CipherType.Card:
intent.PutExtra("autofillFrameworkCardName", savedItem.Card.Name);
intent.PutExtra("autofillFrameworkCardNumber", savedItem.Card.Number);
intent.PutExtra("autofillFrameworkCardExpMonth", savedItem.Card.ExpMonth);
intent.PutExtra("autofillFrameworkCardExpYear", savedItem.Card.ExpYear);
intent.PutExtra("autofillFrameworkCardCode", savedItem.Card.Code);
break;
default:
Toast.MakeText(this, "Unable to save this type of form.", ToastLength.Short).Show();
return;
}
StartActivity(intent);
}
catch (Exception e)
{
#if !FDROID
Crashes.TrackError(e);
#endif
}
StartActivity(intent);
}
}
}

View File

@@ -1,25 +1,24 @@
using Android.App;
using Android.Content.PM;
using Android.Runtime;
using Android.OS;
using Bit.Core;
using System.Linq;
using Bit.App.Abstractions;
using Bit.Core.Utilities;
using Bit.Core.Abstractions;
using System;
using System.IO;
using System;
using Android.Content;
using Bit.Droid.Utilities;
using Bit.Droid.Receivers;
using Bit.App.Models;
using Bit.Core.Enums;
using Android.Nfc;
using System.Linq;
using System.Threading.Tasks;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Nfc;
using Android.OS;
using Android.Runtime;
using AndroidX.Core.Content;
using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using Bit.Droid.Receivers;
using Bit.Droid.Utilities;
using ZXing.Net.Mobile.Android;
using Android.Util;
namespace Bit.Droid
{
@@ -120,6 +119,9 @@ namespace Bit.Droid
base.OnResume();
Xamarin.Essentials.Platform.OnResume();
AppearanceAdjustments();
ThemeManager.UpdateThemeOnPagesAsync();
if (_deviceActionService.SupportsNfc())
{
try

View File

@@ -18,6 +18,8 @@ using Plugin.Fingerprint;
using Xamarin.Android.Net;
using System.Net.Http;
using System.Net;
using Bit.App.Utilities;
using Bit.App.Pages;
#if !FDROID
using Android.Gms.Security;
#endif
@@ -45,6 +47,20 @@ namespace Bit.Droid
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
ServiceContainer.Init(deviceActionService.DeviceUserAgent, Constants.ClearCiphersCacheKey,
Constants.AndroidAllClearCipherCacheKeys);
// TODO: Update when https://github.com/bitwarden/mobile/pull/1662 gets merged
var deleteAccountActionFlowExecutioner = new DeleteAccountActionFlowExecutioner(
ServiceContainer.Resolve<IApiService>("apiService"),
ServiceContainer.Resolve<IMessagingService>("messagingService"),
ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService"),
ServiceContainer.Resolve<IDeviceActionService>("deviceActionService"));
ServiceContainer.Register<IDeleteAccountActionFlowExecutioner>("deleteAccountActionFlowExecutioner", deleteAccountActionFlowExecutioner);
var verificationActionsFlowHelper = new VerificationActionsFlowHelper(
ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService"),
ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService"),
ServiceContainer.Resolve<ICryptoService>("cryptoService"));
ServiceContainer.Register<IVerificationActionsFlowHelper>("verificationActionsFlowHelper", verificationActionsFlowHelper);
}
#if !FDROID
if (Build.VERSION.SdkInt <= BuildVersionCodes.Kitkat)

View File

@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2.15.1" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionCode="1" android:versionName="2.16.4" android:installLocation="internalOnly" package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30"/>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="2048"
android:viewportHeight="2048">
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF777777"
android:pathData="M1824,256C1868,256 1905.67,271.67 1937,303C1968.33,334.33 1984,372 1984,416L1984,1632C1984,1676 1968.33,1713.67 1937,1745C1905.67,1776.33 1868,1792 1824,1792L224,1792C180,1792 142.33,1776.33 111,1745C79.67,1713.67 64,1676 64,1632L64,416C64,372 79.67,334.33 111,303C142.33,271.67 180,256 224,256L1824,256ZM224,384C215.33,384 207.83,387.17 201.5,393.5C195.17,399.83 192,407.33 192,416L192,640L1856,640L1856,416C1856,407.33 1852.83,399.83 1846.5,393.5C1840.17,387.17 1832.67,384 1824,384L224,384ZM1824,1664C1832.67,1664 1840.17,1660.83 1846.5,1654.5C1852.83,1648.17 1856,1640.67 1856,1632L1856,1024L192,1024L192,1632C192,1640.67 195.17,1648.17 201.5,1654.5C207.83,1660.83 215.33,1664 224,1664L1824,1664ZM320,1536L320,1408L576,1408L576,1536L320,1536ZM704,1536L704,1408L1088,1408L1088,1536L704,1536Z" />
android:pathData="M532.864 80h-425.728c-12.067 0.695-23.371 6.129-31.451 15.118s-12.279 20.808-11.686 32.882v256c-0.594 12.074 3.606 23.891 11.686 32.88 8.079 8.992 19.383 14.425 31.451 15.12h425.599c12.090-0.663 23.427-6.083 31.533-15.075 8.109-8.995 12.327-20.832 11.731-32.925v-256c0.595-12.073-3.606-23.891-11.683-32.882-8.080-8.99-19.385-14.424-31.453-15.118v0zM107.264 112h425.6c4.013 0.248 7.766 2.066 10.451 5.059 2.682 2.995 4.077 6.925 3.885 10.941v28.8c0.186 3.465-1.011 6.862-3.328 9.447-2.313 2.585-5.558 4.147-9.024 4.345h-429.728c-3.459-0.207-6.695-1.773-9.003-4.356s-3.501-5.976-3.317-9.436v-28.8c-0.192-4.016 1.204-7.946 3.886-10.941s6.437-4.812 10.45-5.059h0.128zM532.864 399.808h-425.728c-3.978-0.247-7.703-2.038-10.38-4.992-2.677-2.95-4.097-6.832-3.956-10.816v-167.424c-0.183-3.465 1.013-6.862 3.329-9.446s5.559-4.147 9.023-4.345h429.76c3.466 0.198 6.711 1.761 9.024 4.345 2.317 2.584 3.514 5.982 3.328 9.447v167.424c0.192 4.026-1.213 7.965-3.907 10.963-2.697 2.995-6.467 4.806-10.493 5.037v-0.192zM494.496 340.96h-75.296c-2.717 0.358-5.213 1.69-7.021 3.75s-2.803 4.711-2.803 7.45c0 2.743 0.995 5.389 2.803 7.45s4.304 3.395 7.021 3.75h75.424c2.72-0.355 5.216-1.69 7.024-3.75s2.803-4.707 2.803-7.45c0-2.739-0.995-5.389-2.803-7.45s-4.304-3.392-7.024-3.75h-0.128z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1792"
android:viewportHeight="1792">
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M1152,896q0,-106 -75,-181t-181,-75 -181,75 -75,181 75,181 181,75 181,-75 75,-181zM1664,787v222q0,12 -8,23t-20,13l-185,28q-19,54 -39,91 35,50 107,138 10,12 10,25t-9,23q-27,37 -99,108t-94,71q-12,0 -26,-9l-138,-108q-44,23 -91,38 -16,136 -29,186 -7,28 -36,28h-222q-14,0 -24.5,-8.5t-11.5,-21.5l-28,-184q-49,-16 -90,-37l-141,107q-10,9 -25,9 -14,0 -25,-11 -126,-114 -165,-168 -7,-10 -7,-23 0,-12 8,-23 15,-21 51,-66.5t54,-70.5q-27,-50 -41,-99l-183,-27q-13,-2 -21,-12.5t-8,-23.5v-222q0,-12 8,-23t19,-13l186,-28q14,-46 39,-92 -40,-57 -107,-138 -10,-12 -10,-24 0,-10 9,-23 26,-36 98.5,-107.5t94.5,-71.5q13,0 26,10l138,107q44,-23 91,-38 16,-136 29,-186 7,-28 36,-28h222q14,0 24.5,8.5t11.5,21.5l28,184q49,16 90,37l142,-107q9,-9 24,-9 13,0 25,10 129,119 165,170 7,8 7,22 0,12 -8,23 -15,21 -51,66.5t-54,70.5q26,50 41,98l183,28q13,2 21,12.5t8,23.5z" />
android:pathData="M532.989 289.887l-3.872-2.528c-3.197-1.866-5.744-4.667-7.299-8.026-1.558-3.358-2.048-7.113-1.405-10.759v-24.64c-0.682-3.57-0.202-7.266 1.37-10.542s4.154-5.964 7.366-7.666l4.768-2.4c12.013-7.054 20.768-18.547 24.384-32 3.421-13.333 1.661-27.466-4.928-39.552l-25.056-43.872c-7.011-11.727-18.259-20.313-31.418-23.987-13.161-3.674-27.229-2.155-39.303 4.243l-4.384 2.208c-3.286 1.769-6.983 2.63-10.711 2.496-3.731-0.135-7.357-1.261-10.505-3.263-7.082-4.796-14.579-8.951-22.4-12.416-3.28-1.636-6.038-4.157-7.962-7.278s-2.935-6.719-2.918-10.386v-6.528c0.099-6.965-1.197-13.879-3.808-20.335s-6.49-12.326-11.401-17.264c-4.915-4.937-10.765-8.842-17.209-11.486s-13.351-3.972-20.317-3.907h-51.2c-6.952-0.043-13.842 1.301-20.267 3.954s-12.257 6.561-17.154 11.496c-4.896 4.935-8.758 10.797-11.361 17.243s-3.892 13.347-3.794 20.298v5.472c0.032 3.614-0.938 7.165-2.802 10.261s-4.55 5.614-7.758 7.275c-5.691 2.572-11.197 5.533-16.48 8.864l-6.080 3.584c-3.102 2.221-6.788 3.481-10.6 3.623s-7.582-0.839-10.84-2.823l-3.968-1.952c-5.856-3.516-12.377-5.778-19.153-6.642s-13.656-0.314-20.208 1.618c-13.446 3.716-24.885 12.58-31.84 24.672l-24.96 43.68c-3.566 6.048-5.867 12.757-6.763 19.721s-0.37 14.037 1.547 20.791c1.743 6.495 4.779 12.571 8.925 17.866s9.317 9.699 15.203 12.95l2.88 2.848 1.312 0.928c3.197 1.867 5.744 4.667 7.3 8.026s2.046 7.113 1.403 10.758v24.704c0.326 3.533-0.314 7.087-1.853 10.283s-3.918 5.913-6.883 7.861l-4.768 2.4c-11.724 7.217-20.258 18.63-23.866 31.917s-2.020 27.447 4.442 39.603l25.088 43.872c6.806 11.955 18.058 20.739 31.308 24.445 13.25 3.702 27.425 2.026 39.445-4.669l4.352-2.176c3.287-1.792 6.994-2.669 10.736-2.547 3.742 0.125 7.382 1.248 10.544 3.251 7.082 4.797 14.578 8.954 22.4 12.416 3.281 1.635 6.038 4.157 7.962 7.28 1.923 3.12 2.934 6.717 2.918 10.384v5.472c-0.102 6.954 1.185 13.859 3.788 20.31s6.468 12.317 11.368 17.251c4.901 4.938 10.738 8.845 17.169 11.495s13.327 3.987 20.282 3.936h51.2c6.957 0.051 13.856-1.286 20.288-3.936s12.272-6.557 17.175-11.491c4.902-4.938 8.771-10.8 11.379-17.251 2.605-6.451 3.897-13.357 3.798-20.313v-5.472c-0.032-3.613 0.938-7.165 2.803-10.259 1.863-3.098 4.547-5.616 7.757-7.277 5.683-2.567 11.181-5.526 16.448-8.864l1.376-0.8 4.704-2.784c3.111-2.211 6.803-3.466 10.618-3.606 3.815-0.144 7.587 0.832 10.854 2.807l3.968 1.952c5.993 3.568 12.653 5.878 19.565 6.791 6.915 0.912 13.945 0.409 20.659-1.478 6.599-1.805 12.755-4.95 18.080-9.248 5.325-4.295 9.706-9.645 12.864-15.712l24.96-43.68c3.504-5.907 5.757-12.474 6.615-19.289 0.861-6.816 0.307-13.735-1.622-20.327-3.584-13.397-12.298-24.846-24.256-31.873zM319.997 346.752c-17.949 0-35.495-5.322-50.419-15.296-14.924-9.971-26.556-24.144-33.424-40.727s-8.666-34.83-5.165-52.434c3.502-17.604 12.145-33.775 24.837-46.466s28.862-21.335 46.466-24.837c17.604-3.502 35.852-1.704 52.434 5.164s30.755 18.501 40.73 33.425c9.971 14.924 15.293 32.47 15.293 50.419 0 24.069-9.562 47.153-26.579 64.17-17.021 17.021-40.103 26.582-64.173 26.582z" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M320.64 512.32c141.385 0 256-114.615 256-256s-114.615-256-256-256c-141.385 0-256 114.615-256 256s114.615 256 256 256zM488 278.402c3.315 0.796 6.199 2.832 8.055 5.69 1.859 2.858 2.547 6.318 1.93 9.671-8.887 36.99-28.976 70.334-57.529 95.474s-64.173 40.845-101.99 44.976c-6.4 0.64-12.8 0.928-19.2 0.928-34.070-0.307-67.349-10.301-95.948-28.819s-51.337-44.797-65.555-75.757c-0.339-0.387-0.768-0.688-1.248-0.877-0.48-0.185-0.998-0.253-1.511-0.195-0.512 0.055-1.003 0.233-1.43 0.522s-0.78 0.672-1.027 1.127l-8.032 16.576c-1.536 3.181-4.274 5.623-7.611 6.787s-6.999 0.957-10.181-0.579c-3.183-1.536-5.624-4.275-6.789-7.613-1.164-3.334-0.955-6.998 0.581-10.179l24.96-51.49c1.492-3.055 4.099-5.423 7.284-6.614s6.706-1.114 9.836 0.214l53.12 22.4c1.613 0.675 3.078 1.66 4.311 2.901s2.209 2.712 2.874 4.33c0.664 1.618 1.003 3.351 0.998 5.1s-0.356 3.479-1.030 5.094c-0.674 1.614-1.66 3.079-2.901 4.312s-2.712 2.208-4.33 2.873c-1.618 0.663-3.351 1.002-5.1 0.998-1.749-0.007-3.48-0.358-5.093-1.031l-20.832-8.738c-2.624-0.288-3.68 1.6-3.2 2.912 13.19 29.202 35.259 53.495 63.062 69.422s59.924 22.675 91.786 19.283c32.304-3.2 62.791-16.445 87.175-37.872s41.44-49.962 48.762-81.585c0.365-1.711 1.063-3.333 2.055-4.774s2.259-2.671 3.728-3.623c1.469-0.951 3.111-1.603 4.829-1.92 1.721-0.317 3.488-0.291 5.197 0.076zM502.947 157.296c3.331-1.163 6.989-0.962 10.173 0.56 1.622 0.746 3.075 1.811 4.275 3.131 1.203 1.32 2.125 2.867 2.717 4.551s0.838 3.469 0.726 5.25c-0.115 1.781-0.582 3.521-1.383 5.117l-24.928 51.488c-1.498 3.050-4.106 5.412-7.286 6.602-3.184 1.19-6.701 1.118-9.834-0.202l-53.152-22.4c-1.613-0.677-3.079-1.665-4.31-2.907s-2.205-2.715-2.87-4.335c-0.663-1.619-0.998-3.353-0.992-5.103 0.010-1.75 0.361-3.481 1.037-5.095 0.678-1.613 1.664-3.078 2.909-4.31 1.241-1.232 2.714-2.207 4.333-2.87s3.353-1 5.104-0.993c1.75 0.007 3.481 0.359 5.094 1.036l20.832 8.704c2.592 0.288 3.68-1.6 3.2-2.912-13.216-29.171-35.293-53.431-63.094-69.329s-59.911-22.621-91.753-19.216c-32.303 3.198-62.791 16.443-87.175 37.87s-41.437 49.961-48.761 81.585c-0.73 3.458-2.804 6.486-5.765 8.415s-6.569 2.603-10.027 1.874c-3.458-0.73-6.485-2.804-8.415-5.765s-2.603-6.569-1.874-10.027c8.919-36.975 29.038-70.293 57.608-95.403s64.194-40.785 102.008-44.886c6.4-0.64 12.8-0.928 19.2-0.928 34.055 0.283 67.325 10.252 95.923 28.742s51.347 44.737 65.581 75.674c0.339 0.394 0.768 0.7 1.255 0.891 0.483 0.19 1.005 0.261 1.523 0.204 0.515-0.056 1.011-0.238 1.443-0.53 0.429-0.291 0.784-0.683 1.027-1.142l8.032-16.576c1.549-3.173 4.285-5.606 7.619-6.768z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="2048"
android:viewportHeight="2048">
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF777777"
android:pathData="M896,1340C896,1376.67 885.5,1407.83 864.5,1433.5C843.5,1459.17 818.33,1472 789,1472L363,1472C333.67,1472 308.5,1459.17 287.5,1433.5C266.5,1407.83 256,1376.67 256,1340C256,1304 258.5,1270.5 263.5,1239.5C268.5,1208.5 276.67,1178.5 288,1149.5C299.33,1120.5 316.33,1097.67 339,1081C361.67,1064.33 388.67,1056 420,1056C462.67,1098.67 514.67,1120 576,1120C637.33,1120 689.33,1098.67 732,1056C763.33,1056 790.33,1064.33 813,1081C835.67,1097.67 852.67,1120.5 864,1149.5C875.33,1178.5 883.5,1208.5 888.5,1239.5C893.5,1270.5 896,1304 896,1340ZM768,896C768,949.33 749.33,994.67 712,1032C674.67,1069.33 629.33,1088 576,1088C522.67,1088 477.33,1069.33 440,1032C402.67,994.67 384,949.33 384,896C384,842.67 402.67,797.33 440,760C477.33,722.67 522.67,704 576,704C629.33,704 674.67,722.67 712,760C749.33,797.33 768,842.67 768,896ZM1792,1312L1792,1376C1792,1385.33 1789,1393 1783,1399C1777,1405 1769.33,1408 1760,1408L1056,1408C1046.67,1408 1039,1405 1033,1399C1027,1393 1024,1385.33 1024,1376L1024,1312C1024,1302.67 1027,1295 1033,1289C1039,1283 1046.67,1280 1056,1280L1760,1280C1769.33,1280 1777,1283 1783,1289C1789,1295 1792,1302.67 1792,1312ZM1408,1056L1408,1120C1408,1129.33 1405,1137 1399,1143C1393,1149 1385.33,1152 1376,1152L1056,1152C1046.67,1152 1039,1149 1033,1143C1027,1137 1024,1129.33 1024,1120L1024,1056C1024,1046.67 1027,1039 1033,1033C1039,1027 1046.67,1024 1056,1024L1376,1024C1385.33,1024 1393,1027 1399,1033C1405,1039 1408,1046.67 1408,1056ZM1792,1056L1792,1120C1792,1129.33 1789,1137 1783,1143C1777,1149 1769.33,1152 1760,1152L1568,1152C1558.67,1152 1551,1149 1545,1143C1539,1137 1536,1129.33 1536,1120L1536,1056C1536,1046.67 1539,1039 1545,1033C1551,1027 1558.67,1024 1568,1024L1760,1024C1769.33,1024 1777,1027 1783,1033C1789,1039 1792,1046.67 1792,1056ZM1792,800L1792,864C1792,873.33 1789,881 1783,887C1777,893 1769.33,896 1760,896L1056,896C1046.67,896 1039,893 1033,887C1027,881 1024,873.33 1024,864L1024,800C1024,790.67 1027,783 1033,777C1039,771 1046.67,768 1056,768L1760,768C1769.33,768 1777,771 1783,777C1789,783 1792,790.67 1792,800ZM1920,1632L1920,512L128,512L128,1632C128,1640.67 131.17,1648.17 137.5,1654.5C143.83,1660.83 151.33,1664 160,1664L1888,1664C1896.67,1664 1904.17,1660.83 1910.5,1654.5C1916.83,1648.17 1920,1640.67 1920,1632ZM2048,416L2048,1632C2048,1676 2032.33,1713.67 2001,1745C1969.67,1776.33 1932,1792 1888,1792L160,1792C116,1792 78.33,1776.33 47,1745C15.67,1713.67 0,1676 0,1632L0,416C0,372 15.67,334.33 47,303C78.33,271.67 116,256 160,256L1888,256C1932,256 1969.67,271.67 2001,303C2032.33,334.33 2048,372 2048,416Z" />
android:pathData="M261.411 257.983c8.966-7.451 15.421-17.482 18.488-28.73s2.595-23.167-1.349-34.138c-3.945-10.97-11.171-20.461-20.697-27.181s-20.891-10.345-32.548-10.381c-11.658-0.036-23.044 3.518-32.612 10.18s-16.852 16.107-20.863 27.053c-4.012 10.946-4.556 22.862-1.559 34.129s9.39 21.337 18.31 28.843c-13.738 5.811-25.873 14.849-35.375 26.346s-16.095 25.116-19.216 39.704c-0.78 3.654-0.728 7.44 0.153 11.075 0.881 3.632 2.567 7.021 4.935 9.917 2.31 2.864 5.236 5.175 8.559 6.759s6.96 2.403 10.642 2.394h132.928c3.682 0.010 7.318-0.81 10.642-2.394s6.248-3.894 8.558-6.759c2.366-2.896 4.053-6.285 4.939-9.917s0.948-7.418 0.181-11.075c-3.106-14.498-9.639-28.038-19.054-39.491s-21.436-20.483-35.058-26.334v0zM225.123 180.319c6.798 0 13.442 2.016 19.094 5.792s10.056 9.144 12.658 15.423c2.601 6.28 3.282 13.19 1.956 19.857s-4.6 12.791-9.406 17.597c-4.806 4.806-10.93 8.079-17.597 9.406s-13.577 0.645-19.857-1.956c-6.28-2.601-11.648-7.006-15.423-12.658s-5.792-12.297-5.792-19.094c0.008-9.113 3.632-17.85 10.076-24.292s15.18-10.067 24.292-10.076v0zM291.202 331.552h-132.928l-2.368-3.2c3.409-15.714 12.094-29.788 24.61-39.88s28.112-15.596 44.19-15.596c16.079 0 31.673 5.504 44.19 15.596s21.202 24.166 24.61 39.88l-2.304 3.2zM369.376 202.178h80.288c2.825-0.214 5.466-1.487 7.389-3.563 1.926-2.077 2.998-4.804 2.998-7.637s-1.072-5.56-2.998-7.637c-1.923-2.077-4.563-3.35-7.389-3.563h-80.288c-2.822 0.214-5.462 1.487-7.389 3.563s-2.995 4.804-2.995 7.637c0 2.833 1.069 5.56 2.995 7.637s4.567 3.35 7.389 3.563v0zM484.445 309.699h-115.2c-2.825 0.214-5.466 1.486-7.389 3.563-1.926 2.077-2.995 4.805-2.995 7.637s1.069 5.558 2.995 7.639c1.923 2.077 4.563 3.347 7.389 3.562h115.2c2.822-0.214 5.462-1.485 7.389-3.562 1.926-2.080 2.995-4.807 2.995-7.639s-1.069-5.56-2.995-7.637c-1.926-2.077-4.567-3.349-7.389-3.563v0zM484.448 244.738h-115.2c-2.973 0-5.821 1.18-7.92 3.28-2.103 2.101-3.28 4.95-3.28 7.919s1.178 5.819 3.28 7.92c2.099 2.101 4.947 3.281 7.92 3.281h115.2c2.969 0 5.817-1.18 7.92-3.281 2.099-2.101 3.28-4.949 3.28-7.919s-1.181-5.819-3.28-7.919c-2.103-2.1-4.95-3.28-7.92-3.28v0zM544 80h-448c-8.487 0-16.626 3.371-22.627 9.373s-9.373 14.141-9.373 22.627v288c0 8.486 3.371 16.627 9.373 22.627s14.141 9.373 22.627 9.373h448c8.486 0 16.627-3.373 22.627-9.373s9.373-14.141 9.373-22.627v-288c0-8.487-3.373-16.626-9.373-22.627s-14.141-9.373-22.627-9.373v0zM528 400h-416c-4.243 0-8.314-1.687-11.314-4.685-3.001-3.002-4.686-7.072-4.686-11.315v-256c0-4.243 1.686-8.314 4.686-11.314s7.070-4.686 11.314-4.686h418.4c2.816 0.64 13.376 3.712 13.6 13.824v258.176c0 4.243-1.687 8.313-4.685 11.315-3.001 2.998-7.072 4.685-11.315 4.685z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M320 421.763c-4.243 0-8.313-1.687-11.313-4.688s-4.687-7.069-4.687-11.312v-192.001c0-4.243 1.686-8.313 4.687-11.314s7.070-4.686 11.313-4.686c4.243 0 8.313 1.686 11.315 4.686 2.998 3 4.685 7.071 4.685 11.314v192.001c0 4.243-1.687 8.31-4.685 11.312-3.002 3.002-7.072 4.688-11.315 4.688zM320 142.049c10.481 0 18.976-8.495 18.976-18.976s-8.496-18.976-18.976-18.976c-10.48 0-18.976 8.496-18.976 18.976s8.496 18.976 18.976 18.976zM320 512c-50.632 0-100.127-15.014-142.226-43.142-42.099-28.131-74.911-68.112-94.287-114.889-19.376-46.779-24.446-98.252-14.568-147.911s34.26-95.274 70.062-131.076c35.802-35.802 81.417-60.184 131.076-70.061s101.134-4.808 147.911 14.568c46.777 19.376 86.758 52.188 114.89 94.287 28.128 42.099 43.143 91.594 43.143 142.226-0.077 67.872-27.072 132.944-75.065 180.935-47.99 47.993-113.063 74.989-180.935 75.066zM320 32c-44.303 0-87.611 13.138-124.447 37.751s-65.547 59.597-82.501 100.528c-16.954 40.93-21.39 85.969-12.747 129.422s29.977 83.365 61.304 114.693c31.327 31.325 71.24 52.659 114.692 61.303s88.49 4.208 129.422-12.745c40.931-16.957 75.913-45.667 100.528-82.502s37.75-80.145 37.75-124.448c-0.067-59.387-23.689-116.323-65.683-158.317s-98.928-65.615-158.317-65.683v0z"/>
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1792"
android:viewportHeight="1792">
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M640,768h512v-192q0,-106 -75,-181t-181,-75 -181,75 -75,181v192zM1472,864v576q0,40 -28,68t-68,28h-960q-40,0 -68,-28t-28,-68v-576q0,-40 28,-68t68,-28h32v-192q0,-184 132,-316t316,-132 316,132 132,316v192h32q40,0 68,28t28,68z" />
android:pathData="M484.32 163.488h-14.528c-1.142-0.004-2.275-0.233-3.328-0.674-1.056-0.441-2.013-1.086-2.816-1.898-0.807-0.811-1.443-1.773-1.878-2.831-0.432-1.058-0.653-2.191-0.649-3.333v-6.4c0.675-35.916-11.907-70.822-35.341-98.047-23.437-27.225-56.083-44.861-91.699-49.536-19.685-1.895-39.55 0.355-58.314 6.603s-36.011 16.357-50.632 29.675c-14.62 13.318-26.29 29.55-34.255 47.651s-12.054 37.671-11.999 57.447v10.24c0 0.224-0.768 10.944-10.080 11.104h-13.088c-5.76 0.017-11.46 1.168-16.774 3.389s-10.139 5.467-14.198 9.553c-4.059 4.086-7.274 8.932-9.46 14.262s-3.3 11.036-3.278 16.796v260.576c0.025 11.606 4.632 22.733 12.817 30.96s19.29 12.893 30.895 12.976h328.608c11.6-0.077 22.701-4.733 30.883-12.957 8.179-8.224 12.781-19.347 12.797-30.947v-260.608c0.023-5.757-1.091-11.462-3.277-16.789-2.183-5.327-5.395-10.172-9.449-14.257-4.058-4.086-8.877-7.333-14.189-9.555s-11.008-3.377-16.765-3.399v0zM331.808 391.104v43.072c0.083 1.6-0.16 3.2-0.714 4.704-0.557 1.504-1.411 2.877-2.515 4.041-1.101 1.161-2.429 2.087-3.904 2.72-1.472 0.63-3.056 0.957-4.659 0.957-1.602 0-3.188-0.327-4.66-0.957-1.473-0.634-2.8-1.558-3.904-2.72-1.103-1.165-1.958-2.538-2.513-4.041s-0.798-3.104-0.715-4.704v-43.072c-5.285-2.653-9.519-7.014-12.019-12.375s-3.117-11.408-1.753-17.161c1.364-5.753 4.63-10.88 9.269-14.55 4.639-3.667 10.38-5.661 16.295-5.661s11.654 1.993 16.294 5.661c4.64 3.671 7.904 8.797 9.271 14.55 1.363 5.753 0.745 11.801-1.753 17.161s-6.733 9.721-12.019 12.375v0zM429.12 154.752c0.003 1.146-0.217 2.281-0.653 3.341s-1.075 2.023-1.885 2.834c-0.81 0.812-1.769 1.456-2.829 1.895-1.056 0.44-2.192 0.666-3.337 0.666h-196.16c-1.624 0.141-3.258-0.042-4.81-0.536s-2.992-1.291-4.235-2.344c-1.244-1.053-2.266-2.341-3.010-3.792s-1.192-3.032-1.321-4.656v-10.016c-0.043-16.317 3.56-32.439 10.547-47.185s17.179-27.745 29.833-38.047c12.654-10.302 27.451-17.647 43.308-21.497s32.375-4.11 48.344-0.758c24.841 5.834 46.941 19.992 62.624 40.121s24.003 45.020 23.584 70.534v9.44z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1792"
android:viewportHeight="1792">
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF777777"
android:pathData="M896,128q209,0 385.5,103t279.5,279.5 103,385.5 -103,385.5 -279.5,279.5 -385.5,103 -385.5,-103 -279.5,-279.5 -103,-385.5 103,-385.5 279.5,-279.5 385.5,-103zM1170,649q-2,1 -9.5,9.5t-13.5,9.5q2,0 4.5,-5t5,-11 3.5,-7q6,-7 22,-15 14,-6 52,-12 34,-8 51,11 -2,-2 9.5,-13t14.5,-12q3,-2 15,-4.5t15,-7.5l2,-22q-12,1 -17.5,-7t-6.5,-21q0,2 -6,8 0,-7 -4.5,-8t-11.5,1 -9,1q-10,-3 -15,-7.5t-8,-16.5 -4,-15q-2,-5 -9.5,-11t-9.5,-10q-1,-2 -2.5,-5.5t-3,-6.5 -4,-5.5 -5.5,-2.5 -7,5 -7.5,10 -4.5,5q-3,-2 -6,-1.5t-4.5,1 -4.5,3 -5,3.5q-3,2 -8.5,3t-8.5,2q15,-5 -1,-11 -10,-4 -16,-3 9,-4 7.5,-12t-8.5,-14h5q-1,-4 -8.5,-8.5t-17.5,-8.5 -13,-6q-8,-5 -34,-9.5t-33,-0.5q-5,6 -4.5,10.5t4,14 3.5,12.5q1,6 -5.5,13t-6.5,12q0,7 14,15.5t10,21.5q-3,8 -16,16t-16,12q-5,8 -1.5,18.5t10.5,16.5q2,2 1.5,4t-3.5,4.5 -5.5,4 -6.5,3.5l-3,2q-11,5 -20.5,-6t-13.5,-26q-7,-25 -16,-30 -23,-8 -29,1 -5,-13 -41,-26 -25,-9 -58,-4 6,-1 0,-15 -7,-15 -19,-12 3,-6 4,-17.5t1,-13.5q3,-13 12,-23 1,-1 7,-8.5t9.5,-13.5 0.5,-6q35,4 50,-11 5,-5 11.5,-17t10.5,-17q9,-6 14,-5.5t14.5,5.5 14.5,5q14,1 15.5,-11t-7.5,-20q12,1 3,-17 -4,-7 -8,-9 -12,-4 -27,5 -8,4 2,8 -1,-1 -9.5,10.5t-16.5,17.5 -16,-5q-1,-1 -5.5,-13.5t-9.5,-13.5q-8,0 -16,15 3,-8 -11,-15t-24,-8q19,-12 -8,-27 -7,-4 -20.5,-5t-19.5,4q-5,7 -5.5,11.5t5,8 10.5,5.5 11.5,4 8.5,3q14,10 8,14 -2,1 -8.5,3.5t-11.5,4.5 -6,4q-3,4 0,14t-2,14q-5,-5 -9,-17.5t-7,-16.5q7,9 -25,6l-10,-1q-4,0 -16,2t-20.5,1 -13.5,-8q-4,-8 0,-20 1,-4 4,-2 -4,-3 -11,-9.5t-10,-8.5q-46,15 -94,41 6,1 12,-1 5,-2 13,-6.5t10,-5.5q34,-14 42,-7l5,-5q14,16 20,25 -7,-4 -30,-1 -20,6 -22,12 7,12 5,18 -4,-3 -11.5,-10t-14.5,-11 -15,-5q-16,0 -22,1 -146,80 -235,222 7,7 12,8 4,1 5,9t2.5,11 11.5,-3q9,8 3,19 1,-1 44,27 19,17 21,21 3,11 -10,18 -1,-2 -9,-9t-9,-4q-3,5 0.5,18.5t10.5,12.5q-7,0 -9.5,16t-2.5,35.5 -1,23.5l2,1q-3,12 5.5,34.5t21.5,19.5q-13,3 20,43 6,8 8,9 3,2 12,7.5t15,10 10,10.5q4,5 10,22.5t14,23.5q-2,6 9.5,20t10.5,23q-1,0 -2.5,1t-2.5,1q3,7 15.5,14t15.5,13q1,3 2,10t3,11 8,2q2,-20 -24,-62 -15,-25 -17,-29 -3,-5 -5.5,-15.5t-4.5,-14.5q2,0 6,1.5t8.5,3.5 7.5,4 2,3q-3,7 2,17.5t12,18.5 17,19 12,13q6,6 14,19.5t0,13.5q9,0 20,10.5t17,19.5q5,8 8,26t5,24q2,7 8.5,13.5t12.5,9.5l16,8 13,7q5,2 18.5,10.5t21.5,11.5q10,4 16,4t14.5,-2.5 13.5,-3.5q15,-2 29,15t21,21q36,19 55,11 -2,1 0.5,7.5t8,15.5 9,14.5 5.5,8.5q5,6 18,15t18,15q6,-4 7,-9 -3,8 7,20t18,10q14,-3 14,-32 -31,15 -49,-18 0,-1 -2.5,-5.5t-4,-8.5 -2.5,-8.5 0,-7.5 5,-3q9,0 10,-3.5t-2,-12.5 -4,-13q-1,-8 -11,-20t-12,-15q-5,9 -16,8t-16,-9q0,1 -1.5,5.5t-1.5,6.5q-13,0 -15,-1 1,-3 2.5,-17.5t3.5,-22.5q1,-4 5.5,-12t7.5,-14.5 4,-12.5 -4.5,-9.5 -17.5,-2.5q-19,1 -26,20 -1,3 -3,10.5t-5,11.5 -9,7q-7,3 -24,2t-24,-5q-13,-8 -22.5,-29t-9.5,-37q0,-10 2.5,-26.5t3,-25 -5.5,-24.5q3,-2 9,-9.5t10,-10.5q2,-1 4.5,-1.5t4.5,0 4,-1.5 3,-6q-1,-1 -4,-3 -3,-3 -4,-3 7,3 28.5,-1.5t27.5,1.5q15,11 22,-2 0,-1 -2.5,-9.5t-0.5,-13.5q5,27 29,9 3,3 15.5,5t17.5,5q3,2 7,5.5t5.5,4.5 5,-0.5 8.5,-6.5q10,14 12,24 11,40 19,44 7,3 11,2t4.5,-9.5 0,-14 -1.5,-12.5l-1,-8v-18l-1,-8q-15,-3 -18.5,-12t1.5,-18.5 15,-18.5q1,-1 8,-3.5t15.5,-6.5 12.5,-8q21,-19 15,-35 7,0 11,-9 -1,0 -5,-3t-7.5,-5 -4.5,-2q9,-5 2,-16 5,-3 7.5,-11t7.5,-10q9,12 21,2 8,-8 1,-16 5,-7 20.5,-10.5t18.5,-9.5q7,2 8,-2t1,-12 3,-12q4,-5 15,-9t13,-5l17,-11q3,-4 0,-4 18,2 31,-11 10,-11 -6,-20 3,-6 -3,-9.5t-15,-5.5q3,-1 11.5,-0.5t10.5,-1.5q15,-10 -7,-16 -17,-5 -43,12zM1007,1526q206,-36 351,-189 -3,-3 -12.5,-4.5t-12.5,-3.5q-18,-7 -24,-8 1,-7 -2.5,-13t-8,-9 -12.5,-8 -11,-7q-2,-2 -7,-6t-7,-5.5 -7.5,-4.5 -8.5,-2 -10,1l-3,1q-3,1 -5.5,2.5t-5.5,3 -4,3 0,2.5q-21,-17 -36,-22 -5,-1 -11,-5.5t-10.5,-7 -10,-1.5 -11.5,7q-5,5 -6,15t-2,13q-7,-5 0,-17.5t2,-18.5q-3,-6 -10.5,-4.5t-12,4.5 -11.5,8.5 -9,6.5 -8.5,5.5 -8.5,7.5q-3,4 -6,12t-5,11q-2,-4 -11.5,-6.5t-9.5,-5.5q2,10 4,35t5,38q7,31 -12,48 -27,25 -29,40 -4,22 12,26 0,7 -8,20.5t-7,21.5q0,6 2,16z" />
android:pathData="M571.2 205.825c-9.082-45.471-30.339-87.624-61.501-121.963-31.159-34.339-71.056-59.575-115.437-73.018-44.377-13.443-91.573-14.586-136.551-3.311s-86.052 34.55-118.84 67.338c-32.788 32.788-56.062 73.862-67.338 118.84s-10.132 92.173 3.311 136.551c13.442 44.381 38.679 84.279 73.018 115.437 34.339 31.161 76.492 52.419 121.964 61.501 41.367 8.409 84.172 6.442 124.594-5.728 40.419-12.166 77.197-34.157 107.046-64.007s51.84-66.627 64.007-107.046c12.169-40.422 14.138-83.228 5.728-124.594zM186.305 76.481c38.576-28.909 85.49-44.517 133.695-44.48 2.752 0 5.376 0.48 8.128 0.608 9.952 2.88 2.368 11.104 2.368 11.104-34.061 17.672-62.726 44.203-82.975 76.8-9.6 15.488-17.216 15.328-19.68 15.040-14.112-0.608-31.456-20.224-44.608-40.16-1.954-2.963-2.723-6.552-2.154-10.055s2.434-6.665 5.226-8.856v0zM253.505 461.184c-1.923 1.971-4.388 3.328-7.083 3.897s-5.497 0.327-8.054-0.697c-40.582-15.911-75.645-43.305-100.902-78.832s-39.611-77.643-41.306-121.199l9.44-13.888c30.432-11.36 60.416-17.504 68.512-10.496 3.744 3.2 1.184 13.12 0 17.216-22.88 74.143 36.288 93.183 58.624 100.383 2.464 0.8 4.576 1.504 6.4 2.112 23.392 9.024 36.736 22.112 39.712 38.848 0.56 11.645-1.404 23.274-5.757 34.087s-10.99 20.56-19.459 28.57h-0.128zM477.152 414.656c-41.667 41.728-98.183 65.226-157.152 65.344-9.798-0.067-19.581-0.807-29.279-2.208-1.884-0.298-3.663-1.063-5.178-2.221-1.514-1.161-2.716-2.678-3.498-4.419s-1.117-3.648-0.976-5.549c0.14-1.901 0.752-3.741 1.779-5.347v0c14.127-18.771 20.486-42.262 17.76-65.6-3.027-13.315-9.63-25.552-19.099-35.392s-21.44-16.909-34.63-20.448c-1.984-0.768-4.544-1.632-7.488-2.56-30.592-9.856-59.168-23.551-44.192-72.447 7.040-22.848 0.256-34.784-6.656-40.768-14.72-12.8-42.976-8.928-68.96-1.216-2.377 0.642-4.879 0.653-7.262 0.034s-4.563-1.849-6.326-3.566c-1.763-1.718-3.049-3.865-3.73-6.231s-0.734-4.868-0.155-7.26c7.821-33.432 23.251-64.608 45.088-91.104 1.379-1.599 3.102-2.864 5.042-3.698s4.043-1.216 6.151-1.118c2.109 0.099 4.167 0.675 6.020 1.688s3.452 2.431 4.674 4.152c14.304 20.224 35.040 42.4 57.6 43.392h1.6c8.108-0.433 15.946-3.062 22.676-7.605s12.098-10.829 15.532-18.188c25.389-38.702 62.678-68.096 106.239-83.744v0c9.504-2.946 19.648-3.124 29.248-0.512 29.693 11.669 56.55 29.538 78.784 52.416 1.798 1.852 3.053 4.159 3.635 6.674s0.467 5.138-0.333 7.591c-0.8 2.453-2.256 4.641-4.208 6.329s-4.327 2.81-6.87 3.247c-41.088 7.136-94.208 21.184-101.088 46.816-3.2 12.416 2.912 24.48 18.56 35.872 60.288 43.744 77.984 77.344 68.768 91.232-8.49 10.898-14.24 23.673-16.774 37.254-2.534 13.577-1.773 27.568 2.214 40.793 5.907 10.624 15.488 18.726 26.944 22.784 0 0 11.36 6.528 5.664 15.584h-0.128zM512 369.664c-2.966 3.639-6.743 6.531-11.024 8.448-4.285 1.917-8.96 2.807-13.648 2.592-4.595-0.729-8.992-2.409-12.909-4.925-3.917-2.519-7.267-5.821-9.843-9.699-7.584-14.624 2.432-38.944 13.312-55.359 11.296-17.12 16.736-55.68-74.304-121.76-7.648-5.536-10.592-10.080-10.080-11.936 3.2-11.808 52.608-27.072 108.8-34.336 2.845-0.366 5.735 0.123 8.298 1.405 2.567 1.282 4.691 3.299 6.102 5.794 18.557 33.828 27.891 71.942 27.066 110.518s-11.783 76.255-31.769 109.257v0z" />
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="600"
android:viewportHeight="600">
<path
android:fillColor="#FF000000"
android:pathData="M508.757,52.805L68.978,306.52C51.804,316.388 53.987,340.299 71.065,347.51L171.925,389.827L444.522,149.585C449.741,144.936 457.141,152.052 452.682,157.46L224.111,435.94L224.111,512.32C224.111,534.712 251.152,543.536 264.436,527.312L324.686,453.967L442.909,503.496C456.382,509.189 471.753,500.744 474.22,486.227L542.536,76.336C545.762,57.17 525.172,43.317 508.757,52.805Z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1792"
android:viewportHeight="1792">
android:width="20dp"
android:height="16dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M491,1536l91,-91 -235,-235 -91,91v107h128v128h107zM1014,608q0,-22 -22,-22 -10,0 -17,7l-542,542q-7,7 -7,17 0,22 22,22 10,0 17,-7l542,-542q7,-7 7,-17zM960,416l416,416 -832,832h-416v-416zM1643,512q0,53 -37,90l-166,166 -416,-416 166,-165q36,-38 90,-38 53,0 91,38l235,234q37,39 37,91z" />
android:pathData="M558.781 17.216c-6.342-6.397-14.083-11.239-22.608-14.148-8.528-2.909-17.613-3.805-26.544-2.619-20.425 3.183-39.178 13.174-53.216 28.352l-323.807 323.872c-11.904 11.872-21.977 25.453-29.888 40.288l-33.696 64.64c-4.079 6.957-5.793 15.046-4.887 23.059s4.382 15.517 9.911 21.389c3.263 3.216 7.133 5.753 11.386 7.462s8.8 2.554 13.382 2.489c6.858-0.067 13.599-1.792 19.648-5.024l64.512-33.632c14.925-7.888 28.573-17.984 40.48-29.952l323.744-323.808c15.187-14.022 25.191-32.763 28.384-53.184 1.159-8.938 0.246-18.022-2.669-26.549-2.912-8.529-7.747-16.273-14.131-22.634v0zM483.741 137.6l-283.103 282.976c-9.575 9.632-20.546 17.767-32.544 24.128l-64.576 33.664c-3.2 1.76-5.76 1.6-6.656 0.736s-0.992-3.2 0.768-6.688l33.728-64.512c6.355-11.949 14.466-22.873 24.064-32.416l282.975-282.688c0.599-0.624 1.315-1.121 2.112-1.461 0.793-0.34 1.648-0.514 2.512-0.514s1.721 0.175 2.515 0.514c0.793 0.34 1.514 0.837 2.109 1.461l36.032 35.2c0.659 0.612 1.187 1.352 1.549 2.175s0.55 1.712 0.557 2.611c0.007 0.899-0.17 1.79-0.522 2.618s-0.867 1.575-1.52 2.196v0zM524.381 96.928l-16.352 16.384c-1.034 0.882-2.352 1.365-3.712 1.365s-2.675-0.484-3.712-1.365l-38.4-37.568c-0.803-0.851-1.286-1.957-1.36-3.125-0.077-1.168 0.256-2.326 0.944-3.275l17.376-17.376c8.906-10.032 20.915-16.791 34.112-19.2 1.222-0.153 2.451-0.227 3.68-0.224 3.517-0.046 7.005 0.616 10.259 1.947s6.208 3.302 8.685 5.797c13.76 13.472 9.216 35.744-11.52 56.48v0.16z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
android:width="20dp"
android:height="16dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M560 237.568h-208c-4.243 0-8.313-1.686-11.315-4.686-2.998-3-4.685-7.070-4.685-11.314v-205.568c0-4.244-1.687-8.313-4.685-11.313-3.002-3.001-7.072-4.686-11.315-4.686s-8.313 1.685-11.313 4.686c-3 3.001-4.687 7.070-4.687 11.313v205.568c0 4.244-1.686 8.314-4.687 11.314s-7.070 4.686-11.313 4.686h-208c-2.101 0-4.182 0.414-6.123 1.218s-3.705 1.982-5.191 3.469c-1.486 1.486-2.665 3.25-3.469 5.19s-1.218 4.022-1.218 6.123c0 2.101 0.414 4.182 1.218 6.123s1.983 3.705 3.469 5.19c1.486 1.486 3.249 2.664 5.191 3.469s4.022 1.218 6.123 1.218h208c4.243 0 8.313 1.686 11.313 4.687s4.687 7.070 4.687 11.313v210.432c0 4.243 1.686 8.313 4.687 11.315 3 2.998 7.070 4.685 11.313 4.685s8.313-1.687 11.315-4.685c2.998-3.002 4.685-7.072 4.685-11.315v-210.432c0-4.243 1.687-8.313 4.685-11.313 3.002-3 7.072-4.687 11.315-4.687h208c4.243 0 8.313-1.686 11.315-4.687 2.999-3 4.685-7.070 4.685-11.314s-1.687-8.314-4.685-11.314c-3.001-3-7.072-4.686-11.315-4.686v0z"/>
</vector>

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="128"
android:viewportHeight="128">
<path
android:fillColor="#FF000000"
android:pathData="M82.292,41.269C77.427,37.45 71.296,35.172 64.638,35.172C48.838,35.172 36.011,47.999 36.011,63.799C36.011,79.599 48.838,92.426 64.638,92.426C74.998,92.426 84.08,86.911 89.105,78.66C89.198,78.504 89.351,78.394 89.527,78.353C89.704,78.313 89.889,78.346 90.04,78.446C92.453,80.028 101.659,86.07 104.243,87.765C104.622,88.014 104.732,88.52 104.491,88.903C96.08,102.14 81.286,110.933 64.454,110.933C38.295,110.933 17.057,89.695 17.057,63.537C17.057,37.378 38.295,16.14 64.454,16.14C77.501,16.14 89.324,21.423 97.899,29.965L106.199,23.954C106.758,23.549 107.496,23.486 108.116,23.791C108.736,24.095 109.137,24.718 109.158,25.408C109.406,33.597 110.018,53.82 110.255,61.641C110.277,62.353 109.945,63.03 109.368,63.448C108.792,63.867 108.046,63.973 107.376,63.732C99.85,61.027 80.127,53.94 72.734,51.283C72.175,51.082 71.773,50.589 71.69,50.001C71.606,49.413 71.855,48.827 72.336,48.479L82.292,41.269Z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
android:width="25dp"
android:height="20dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M560.509 400.576l-90.304-90.56c-4.509-4.373-7.69-9.932-9.175-16.037s-1.209-12.504 0.791-18.459c13.549-38.522 15.271-80.213 4.947-119.721-10.327-39.507-32.224-75.027-62.883-101.996s-68.681-44.158-109.185-49.358c-40.501-5.2-81.633 1.826-118.112 20.176s-66.639 47.186-86.609 82.803c-19.969 35.618-28.835 76.392-25.459 117.087s18.84 79.45 44.406 111.29c25.566 31.84 60.066 55.312 99.070 67.399 42.909 13.382 89.040 12.189 131.198-3.392 5.974-2.064 12.413-2.377 18.56-0.902 6.144 1.472 11.741 4.672 16.128 9.223l89.6 89.952c4.906 4.909 10.729 8.806 17.139 11.462 6.409 2.659 13.283 4.026 20.221 4.026 6.941 0 13.811-1.366 20.224-4.026 6.409-2.656 12.234-6.553 17.136-11.462l22.4-22.4c9.923-9.942 15.495-23.411 15.495-37.456s-5.571-27.514-15.495-37.456l-0.096-0.192zM104.318 253.344c-8.181-29.267-8.441-60.183-0.752-89.584s23.049-56.232 44.509-77.748c21.461-21.516 48.252-36.946 77.633-44.709s60.297-7.584 89.585 0.522c28.303 7.74 54.098 22.735 74.827 43.501 20.733 20.766 35.687 46.583 43.379 74.899 8.183 29.267 8.442 60.183 0.755 89.584-7.69 29.401-23.050 56.232-44.512 77.747-21.459 21.517-48.25 36.947-77.632 44.711-29.381 7.763-60.298 7.584-89.586-0.522-28.303-7.741-54.097-22.736-74.829-43.501s-35.684-46.582-43.379-74.899zM536.317 451.264l-22.4 22.4c-1.728 1.744-3.783 3.127-6.048 4.070s-4.697 1.427-7.152 1.427c-2.454 0-4.883-0.483-7.149-1.427s-4.32-2.327-6.051-4.070l-88.768-88.992c-1.351-1.376-2.394-3.024-3.069-4.832-0.672-1.808-0.957-3.735-0.835-5.661 0.118-1.926 0.643-3.805 1.536-5.514 0.896-1.709 2.137-3.213 3.648-4.409 9.808-8.221 18.829-17.337 26.944-27.232 1.19-1.526 2.688-2.787 4.397-3.696s3.591-1.443 5.52-1.575c1.93-0.131 3.869 0.151 5.683 0.822 1.815 0.669 3.469 1.719 4.848 3.072l88.896 89.088c3.488 3.529 5.443 8.288 5.443 13.248s-1.955 9.721-5.443 13.248v0.032z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M418.883 157.792c0 0 9.28-7.552 15.36-0.512 5.344 6.144-1.472 14.112-1.472 14.112l-176.226 194.976c-3.936 4.57-6.075 10.416-6.016 16.448l0.768 112.32c0.046 3.571 1.213 7.040 3.338 9.911s5.099 5.002 8.502 6.089c1.692 0.567 3.464 0.861 5.248 0.864 2.682 0.003 5.327-0.624 7.724-1.827 2.396-1.207 4.474-2.96 6.069-5.117l49.666-67.2c2.72-3.664 6.576-6.329 10.969-7.581 4.39-1.248 9.072-1.014 13.318 0.669l108.64 42.88c2.333 0.921 4.839 1.325 7.341 1.175 2.505-0.151 4.947-0.845 7.155-2.038 2.195-1.184 4.106-2.839 5.587-4.848 1.481-2.007 2.502-4.32 2.989-6.768l87.84-441.056c0.634-3.203 0.33-6.521-0.88-9.553s-3.27-5.65-5.936-7.535c-2.665-1.909-5.824-3.012-9.097-3.176s-6.525 0.616-9.366 2.248l-477.858 273.376c-2.722 1.565-4.957 3.854-6.457 6.613s-2.206 5.879-2.041 9.014c0.166 3.135 1.197 6.164 2.98 8.75s4.246 4.625 7.118 5.895l106.080 48.256c5.627 3.837 12.391 5.645 19.181 5.133 6.791-0.509 13.206-3.312 18.195-7.949z" />
</vector>

View File

@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1792"
android:viewportHeight="1792">
android:width="640dp"
android:height="512dp"
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:pathData="M1344,960v-640h-448v1137q119,-63 213,-137 235,-184 235,-360zM1536,192v768q0,86 -33.5,170.5t-83,150 -118,127.5 -126.5,103 -121,77.5 -89.5,49.5 -42.5,20q-12,6 -26,6t-26,-6q-16,-7 -42.5,-20t-89.5,-49.5 -121,-77.5 -126.5,-103 -118,-127.5 -83,-150 -33.5,-170.5v-768q0,-26 19,-45t45,-19h1152q26,0 45,19t19,45z" />
android:pathData="M526.976 6.401c-1.929-2.029-4.253-3.644-6.826-4.745-2.576-1.101-5.351-1.663-8.151-1.655h-383.998c-2.802-0.016-5.576 0.543-8.153 1.645s-4.898 2.719-6.823 4.755c-2.031 1.928-3.647 4.252-4.748 6.827s-1.663 5.348-1.653 8.149v256c0.075 19.489 3.855 38.786 11.136 56.863 6.93 17.843 16.24 34.669 27.68 50.016 11.758 15.37 24.924 29.606 39.328 42.528 13.368 12.256 27.44 23.721 42.144 34.336 12.8 9.088 26.24 17.696 40.32 25.824s24.021 13.623 29.824 16.48c5.856 2.88 10.592 5.152 14.112 6.656 2.752 1.325 5.778 1.984 8.83 1.92 3.011 0.042 5.987-0.653 8.672-2.016 3.584-1.568 8.256-3.776 14.176-6.656s16-8.384 29.824-16.48c13.824-8.096 27.424-16.736 40.32-25.824 14.723-10.618 28.816-22.083 42.208-34.336 14.419-12.906 27.587-27.146 39.328-42.528 11.43-15.353 20.739-32.176 27.68-50.016 7.293-18.074 11.072-37.373 11.136-56.863v-256c0.013-2.784-0.544-5.541-1.641-8.101-1.095-2.559-2.704-4.867-4.726-6.779v0zM477.472 279.712c0 92.799-157.472 172.512-157.472 172.512v-397.375h157.472v224.864z" />
</vector>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="10dp" />
<TextView
android:id="@+id/txtLoading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="15dp"
android:gravity="center|left"
android:textSize="18sp" />
</LinearLayout>
</RelativeLayout>

View File

@@ -77,6 +77,9 @@
<compatibility-package
android:name="com.kiwibrowser.browser"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.kiwibrowser.browser.dev"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.microsoft.emmx"
android:maxLongVersionCode="10000000000"/>

View File

@@ -1,6 +1,7 @@
#if !FDROID
using System;
using System.Threading.Tasks;
using AndroidX.Core.App;
using Bit.App.Abstractions;
using Bit.Core;
using Bit.Core.Abstractions;
@@ -21,6 +22,8 @@ namespace Bit.Droid.Services
_pushNotificationListenerService = pushNotificationListenerService;
}
public bool IsRegisteredForPush => NotificationManagerCompat.From(Android.App.Application.Context)?.AreNotificationsEnabled() ?? false;
public async Task<string> GetTokenAsync()
{
return await _storageService.GetAsync<string>(Constants.PushCurrentTokenKey);

View File

@@ -13,6 +13,7 @@ using Android.OS;
using Android.Provider;
using Android.Text;
using Android.Text.Method;
using Android.Views;
using Android.Views.Autofill;
using Android.Views.InputMethods;
using Android.Webkit;
@@ -27,6 +28,7 @@ using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Bit.Droid.Autofill;
using Bit.Droid.Utilities;
using Plugin.CurrentActivity;
namespace Bit.Droid.Services
@@ -37,7 +39,9 @@ namespace Bit.Droid.Services
private readonly IMessagingService _messagingService;
private readonly IBroadcasterService _broadcasterService;
private readonly Func<IEventService> _eventServiceFunc;
private ProgressDialog _progressDialog;
private AlertDialog _progressDialog;
object _progressDialogLock = new object();
private bool _cameraPermissionsDenied;
private Toast _toast;
private string _userAgent;
@@ -108,22 +112,101 @@ namespace Bit.Droid.Services
{
await HideLoadingAsync();
}
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
_progressDialog = new ProgressDialog(activity);
_progressDialog.SetMessage(text);
_progressDialog.SetCancelable(false);
var activity = CrossCurrentActivity.Current.Activity;
var inflater = (LayoutInflater)activity.GetSystemService(Context.LayoutInflaterService);
var dialogView = inflater.Inflate(Resource.Layout.progress_dialog_layout, null);
var txtLoading = dialogView.FindViewById<TextView>(Resource.Id.txtLoading);
txtLoading.Text = text;
txtLoading.SetTextColor(ThemeHelpers.TextColor);
_progressDialog = new AlertDialog.Builder(activity)
.SetView(dialogView)
.SetCancelable(false)
.Create();
_progressDialog.Show();
}
public Task HideLoadingAsync()
{
if (_progressDialog != null)
// Based on https://github.com/redth-org/AndHUD/blob/master/AndHUD/AndHUD.cs
lock (_progressDialogLock)
{
_progressDialog.Dismiss();
_progressDialog.Dispose();
_progressDialog = null;
if (_progressDialog is null)
{
return Task.CompletedTask;
}
void actionDismiss()
{
try
{
if (IsAlive(_progressDialog) && IsAlive(_progressDialog.Window))
{
_progressDialog.Hide();
_progressDialog.Dismiss();
}
}
catch
{
// ignore
}
_progressDialog = null;
}
// First try the SynchronizationContext
if (Application.SynchronizationContext != null)
{
Application.SynchronizationContext.Send(state => actionDismiss(), null);
return Task.CompletedTask;
}
// Otherwise try OwnerActivity on dialog
var ownerActivity = _progressDialog?.OwnerActivity;
if (IsAlive(ownerActivity))
{
ownerActivity.RunOnUiThread(actionDismiss);
return Task.CompletedTask;
}
// Otherwise try get it from the Window Context
if (_progressDialog?.Window?.Context is Activity windowActivity && IsAlive(windowActivity))
{
windowActivity.RunOnUiThread(actionDismiss);
return Task.CompletedTask;
}
// Finally if all else fails, let's see if current activity is MainActivity
if (CrossCurrentActivity.Current.Activity is MainActivity activity && IsAlive(activity))
{
activity.RunOnUiThread(actionDismiss);
return Task.CompletedTask;
}
return Task.CompletedTask;
}
return Task.FromResult(0);
}
bool IsAlive(Java.Lang.Object @object)
{
if (@object == null)
return false;
if (@object.Handle == IntPtr.Zero)
return false;
if (@object is Activity activity)
{
if (activity.IsFinishing)
return false;
if (activity.IsDestroyed)
return false;
}
return true;
}
public bool OpenFile(byte[] fileData, string id, string fileName)

View File

@@ -15,7 +15,7 @@ using Java.Lang;
namespace Bit.Droid.Tile
{
[Service(Permission = Android.Manifest.Permission.BindQuickSettingsTile, Label = "@string/PasswordGenerator",
Icon = "@drawable/refresh")]
Icon = "@drawable/generate")]
[IntentFilter(new string[] { ActionQsTile })]
[Register("com.x8bit.bitwarden.GeneratorTileService")]
public class GeneratorTileService : TileService

View File

@@ -36,6 +36,10 @@ namespace Bit.Droid.Utilities
{
get => ThemeManager.GetResourceColor("SwitchThumbColor").ToAndroid();
}
public static Color TextColor
{
get => ThemeManager.GetResourceColor("TextColor").ToAndroid();
}
public static void SetAppearance(string theme, bool osDarkModeEnabled)
{

View File

@@ -1,45 +0,0 @@
using Bit.App.Pages;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Abstractions
{
public interface INavigationService
{
/// <summary>
/// Sets the viewmodel to be the main page of the application
/// </summary>
void PresentAsMainPage(BaseViewModel viewModel);
/// <summary>
/// Sets the viewmodel as the main page of the application, and wraps its page within a Navigation page
/// </summary>
void PresentAsNavigatableMainPage(BaseViewModel viewModel);
/// <summary>
/// Navigate to the given page on top of the current navigation stack
/// </summary>
Task NavigateTo(BaseViewModel viewModel);
/// <summary>
/// Navigate to the previous item in the navigation stack
/// </summary>
Task NavigateBack();
/// <summary>
/// Navigate back to the element at the root of the navigation stack
/// </summary>
Task NavigateBackToRoot();
}
public interface IViewLocator
{
Page CreateAndBindPageFor<TViewModel>(TViewModel viewModel) where TViewModel : BaseViewModel;
}
public interface IMainPage
{
Page MainPage { get; set; }
}
}

View File

@@ -4,6 +4,7 @@ namespace Bit.App.Abstractions
{
public interface IPushNotificationService
{
bool IsRegisteredForPush { get; }
Task<string> GetTokenAsync();
Task RegisterAsync();
Task UnregisterAsync();

View File

@@ -20,6 +20,7 @@
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2125" />
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
<PackageReference Include="Xamarin.CommunityToolkit" Version="1.3.1" />
</ItemGroup>
<ItemGroup>
@@ -414,5 +415,6 @@
<ItemGroup>
<None Remove="Behaviors\" />
<None Remove="Xamarin.CommunityToolkit" />
</ItemGroup>
</Project>

View File

@@ -8,6 +8,7 @@ using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
@@ -15,7 +16,7 @@ using Xamarin.Forms.Xaml;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace Bit.App
{
public partial class App : Application, IMainPage
public partial class App : Application
{
private readonly IUserService _userService;
private readonly IBroadcasterService _broadcasterService;
@@ -51,8 +52,6 @@ namespace Bit.App
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
var navigator = new NavigationService(this, new ViewLocator());
Bootstrap();
_broadcasterService.Subscribe(nameof(App), async (message) =>
{
@@ -98,7 +97,7 @@ namespace Bit.App
{
if (Device.RuntimePlatform == Device.iOS)
{
ResumedAsync();
ResumedAsync().FireAndForget();
}
}
else if (message.Command == "slept")
@@ -178,6 +177,8 @@ namespace Bit.App
if (Device.RuntimePlatform == Device.Android)
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
// Reset delay on every start
_vaultTimeoutService.DelayLockAndLogoutMs = null;
}
_messagingService.Send("startEventTimer");
}
@@ -204,21 +205,21 @@ namespace Bit.App
_isResumed = true;
if (Device.RuntimePlatform == Device.Android)
{
ResumedAsync();
ResumedAsync().FireAndForget();
}
}
private async Task SleptAsync()
{
await HandleVaultTimeoutAsync();
await _vaultTimeoutService.CheckVaultTimeoutAsync();
_messagingService.Send("stopEventTimer");
}
private async void ResumedAsync()
private async Task ResumedAsync()
{
UpdateTheme();
await _vaultTimeoutService.CheckVaultTimeoutAsync();
_messagingService.Send("startEventTimer");
await UpdateThemeAsync();
await ClearCacheIfNeededAsync();
Prime();
SyncIfNeeded();
@@ -228,6 +229,15 @@ namespace Bit.App
}
}
public async Task UpdateThemeAsync()
{
await Device.InvokeOnMainThreadAsync(() =>
{
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
_messagingService.Send("updatedTheme");
});
}
private void SetCulture()
{
// Calendars are removed by linker. ref https://bugzilla.xamarin.com/show_bug.cgi?id=59077
@@ -281,33 +291,6 @@ namespace Bit.App
}
}
private async Task HandleVaultTimeoutAsync()
{
if (await _vaultTimeoutService.IsLockedAsync())
{
return;
}
var authed = await _userService.IsAuthenticatedAsync();
if (!authed)
{
return;
}
var vaultTimeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
vaultTimeout = vaultTimeout.GetValueOrDefault(-1);
if (vaultTimeout == 0)
{
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey);
if (action == "logOut")
{
await _vaultTimeoutService.LogOutAsync();
}
else
{
await _vaultTimeoutService.LockAsync(true);
}
}
}
private async Task ClearCacheIfNeededAsync()
{
var lastClear = await _storageService.GetAsync<DateTime?>(Constants.LastFileCacheClearKey);
@@ -356,7 +339,7 @@ namespace Bit.App
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
Current.RequestedThemeChanged += (s, a) =>
{
UpdateTheme();
UpdateThemeAsync();
};
Current.MainPage = new HomePage();
var mainPageTask = SetMainPageAsync();
@@ -380,15 +363,6 @@ namespace Bit.App
});
}
private void UpdateTheme()
{
Device.BeginInvokeOnMainThread(() =>
{
ThemeManager.SetTheme(Device.RuntimePlatform == Device.Android, Current.Resources);
_messagingService.Send("updatedTheme");
});
}
private async Task LockedAsync(bool autoPromptBiometric)
{
await _stateService.PurgeAsync();

View File

@@ -5,6 +5,7 @@
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
@@ -27,7 +28,7 @@
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<controls:FaLabel
<controls:IconLabel
Grid.Column="0"
HorizontalOptions="Center"
VerticalOptions="Center"
@@ -76,25 +77,25 @@
Text="{Binding Cipher.SubTitle}"
IsVisible="{Binding Source={RelativeSource Self}, Path=Text,
Converter={StaticResource stringHasValueConverter}}"/>
<controls:FaLabel
<controls:IconLabel
Grid.Column="1"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1b2;"
Text="{Binding Source={x:Static core:BitwardenIcons.Collection}}"
IsVisible="{Binding Cipher.Shared, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Shared}" />
<controls:FaLabel
<controls:IconLabel
Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf0c6;"
Text="{Binding Source={x:Static core:BitwardenIcons.Paperclip}}"
IsVisible="{Binding Cipher.HasAttachments, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Attachments}" />

View File

@@ -2,18 +2,18 @@
namespace Bit.App.Controls
{
public class FaButton : Button
public class IconButton : Button
{
public FaButton()
public IconButton()
{
Padding = 0;
switch (Device.RuntimePlatform)
{
case Device.iOS:
FontFamily = "FontAwesome";
FontFamily = "bwi-font";
break;
case Device.Android:
FontFamily = "FontAwesome.ttf#FontAwesome";
FontFamily = "bwi-font.ttf#bwi-font";
break;
}
}

View File

@@ -2,17 +2,17 @@
namespace Bit.App.Controls
{
public class FaLabel : Label
public class IconLabel : Label
{
public FaLabel()
public IconLabel()
{
switch (Device.RuntimePlatform)
{
case Device.iOS:
FontFamily = "FontAwesome";
FontFamily = "bwi-font";
break;
case Device.Android:
FontFamily = "FontAwesome.ttf#FontAwesome";
FontFamily = "bwi-font.ttf#bwi-font";
break;
}
}

View File

@@ -4,6 +4,7 @@
x:Class="Bit.App.Controls.SendViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
@@ -23,7 +24,7 @@
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<controls:FaLabel
<controls:IconLabel
Grid.Row="0"
Grid.Column="0"
HorizontalOptions="Center"
@@ -60,58 +61,58 @@
Grid.ColumnSpan="6"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Send.DisplayDate}" />
<controls:FaLabel
<controls:IconLabel
Grid.Column="1"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf071;"
Text="{Binding Source={x:Static core:BitwardenIcons.ExclamationTriangle}}"
IsVisible="{Binding Send.Disabled, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Disabled}" />
<controls:FaLabel
<controls:IconLabel
Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf084;"
Text="{Binding Source={x:Static core:BitwardenIcons.Key}}"
IsVisible="{Binding Send.HasPassword, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Password}" />
<controls:FaLabel
<controls:IconLabel
Grid.Column="3"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf05e;"
Text="{Binding Source={x:Static core:BitwardenIcons.Ban}}"
IsVisible="{Binding Send.MaxAccessCountReached, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n MaxAccessCountReached}" />
<controls:FaLabel
<controls:IconLabel
Grid.Column="4"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf017;"
Text="{Binding Source={x:Static core:BitwardenIcons.Clock}}"
IsVisible="{Binding Send.Expired, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Expired}" />
<controls:FaLabel
<controls:IconLabel
Grid.Column="5"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1f8;"
Text="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
IsVisible="{Binding Send.PendingDelete, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n PendingDelete}" />

View File

@@ -21,6 +21,7 @@ namespace Bit.App.Models
public string SaveCardCode { get; set; }
public bool IosExtension { get; set; }
public Tuple<SendType, string, byte[], string> CreateSend { get; set; }
public bool CopyInsteadOfShareAfterSaving { get; set; }
public void SetAllFrom(AppOptions o)
{
@@ -44,6 +45,7 @@ namespace Bit.App.Models
SaveCardCode = o.SaveCardCode;
IosExtension = o.IosExtension;
CreateSend = o.CreateSend;
CopyInsteadOfShareAfterSaving = o.CopyInsteadOfShareAfterSaving;
}
}
}

View File

@@ -1,6 +1,7 @@
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Exceptions;
using Bit.Core.Utilities;
@@ -12,21 +13,13 @@ namespace Bit.App.Pages
{
public class DeleteAccountViewModel : BaseViewModel
{
readonly IApiService _apiService;
readonly IPasswordRepromptService _passwordRepromptService;
readonly IMessagingService _messagingService;
readonly ICryptoService _cryptoService;
readonly IPlatformUtilsService _platformUtilsService;
readonly IDeviceActionService _deviceActionService;
readonly IVerificationActionsFlowHelper _verificationActionsFlowHelper;
public DeleteAccountViewModel()
{
_apiService = ServiceContainer.Resolve<IApiService>("apiService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_verificationActionsFlowHelper = ServiceContainer.Resolve<IVerificationActionsFlowHelper>("verificationActionsFlowHelper");
PageTitle = AppResources.DeleteAccount;
}
@@ -42,18 +35,53 @@ namespace Bit.App.Pages
return;
}
var (password, valid) = await _passwordRepromptService.ShowPasswordPromptAndGetItAsync();
if (!valid)
{
return;
}
await _verificationActionsFlowHelper
.Configure(VerificationFlowAction.DeleteAccount,
null,
AppResources.DeleteAccount,
true)
.ValidateAndExecuteAsync();
}
catch (System.Exception ex)
{
#if !FDROID
Crashes.TrackError(ex);
#endif
await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred);
}
}
}
public interface IDeleteAccountActionFlowExecutioner : IActionFlowExecutioner { }
public class DeleteAccountActionFlowExecutioner : IDeleteAccountActionFlowExecutioner
{
readonly IApiService _apiService;
readonly IMessagingService _messagingService;
readonly IPlatformUtilsService _platformUtilsService;
readonly IDeviceActionService _deviceActionService;
public DeleteAccountActionFlowExecutioner(IApiService apiService,
IMessagingService messagingService,
IPlatformUtilsService platformUtilsService,
IDeviceActionService deviceActionService)
{
_apiService = apiService;
_messagingService = messagingService;
_platformUtilsService = platformUtilsService;
_deviceActionService = deviceActionService;
}
public async Task Execute(IActionFlowParmeters parameters)
{
try
{
await _deviceActionService.ShowLoadingAsync(AppResources.DeletingYourAccount);
var masterPasswordHashKey = await _cryptoService.HashPasswordAsync(password, null);
await _apiService.DeleteAccountAsync(new Core.Models.Request.DeleteAccountRequest
{
MasterPasswordHash = masterPasswordHashKey
MasterPasswordHash = parameters.VerificationType == Core.Enums.VerificationType.MasterPassword ? parameters.Secret : (string)null,
OTP = parameters.VerificationType == Core.Enums.VerificationType.OTP ? parameters.Secret : (string)null
});
await _deviceActionService.HideLoadingAsync();

View File

@@ -6,6 +6,7 @@
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:HomeViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
@@ -17,19 +18,19 @@
</ContentPage.ToolbarItems>
<StackLayout Spacing="0" Padding="10, 5">
<controls:FaButton Text="&#xf013;"
<controls:IconButton Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
StyleClass="btn-muted, btn-icon, btn-icon-platform"
HorizontalOptions="Start"
Clicked="Environment_Clicked"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}">
<controls:FaButton.Margin>
<controls:IconButton.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0, 10, 0, 0" />
<On Platform="Android" Value="0" />
</OnPlatform>
</controls:FaButton.Margin>
</controls:FaButton>
</controls:IconButton.Margin>
</controls:IconButton>
<StackLayout VerticalOptions="CenterAndExpand" Spacing="20">
<Image
x:Name="_logo"

View File

@@ -63,7 +63,7 @@
Grid.Column="0"
ReturnType="Go"
ReturnCommand="{Binding SubmitCommand}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"
@@ -102,7 +102,7 @@
Grid.Column="0"
ReturnType="Go"
ReturnCommand="{Binding SubmitCommand}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"

View File

@@ -1,16 +1,18 @@
using Bit.App.Abstractions;
using Bit.App.Models;
using System;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using Bit.App.Utilities;
using Bit.Core.Models.Request;
using Bit.Core.Utilities;
using Xamarin.Forms;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
namespace Bit.App.Pages
{
@@ -122,7 +124,7 @@ namespace Bit.App.Pages
public Command SubmitCommand { get; }
public Command TogglePasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string MasterPassword { get; set; }
public string Pin { get; set; }
public Action UnlockedAction { get; set; }
@@ -135,11 +137,20 @@ namespace Bit.App.Pages
// Users with key connector and without biometric or pin has no MP to unlock with
_usingKeyConnector = await _keyConnectorService.GetUsesKeyConnector();
if ( _usingKeyConnector && !(BiometricLock || PinLock))
if (_usingKeyConnector && !(BiometricLock || PinLock))
{
await _vaultTimeoutService.LogOutAsync();
return;
}
_email = await _userService.GetEmailAsync();
if (string.IsNullOrWhiteSpace(_email))
{
await _vaultTimeoutService.LogOutAsync();
#if !FDROID
Crashes.TrackError(new NullReferenceException("Email not found in storage"));
#endif
return;
}
var webVault = _environmentService.GetWebVaultUrl();
if (string.IsNullOrWhiteSpace(webVault))
{

View File

@@ -70,7 +70,7 @@
Grid.Column="0"
ReturnType="Go"
ReturnCommand="{Binding LogInCommand}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"

View File

@@ -69,7 +69,7 @@ namespace Bit.App.Pages
public Command LogInCommand { get; }
public Command TogglePasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public bool RememberEmail { get; set; }
public Action StartTwoFactorAction { get; set; }
public Action LogInSuccessAction { get; set; }

View File

@@ -116,7 +116,7 @@ namespace Bit.App.Pages
var redirectUri = "bitwarden://sso-callback";
var url = _apiService.IdentityBaseUrl + "/connect/authorize?" +
"client_id=" + _platformUtilsService.IdentityClientId + "&" +
"client_id=" + _platformUtilsService.GetClientType().GetString() + "&" +
"redirect_uri=" + Uri.EscapeDataString(redirectUri) + "&" +
"response_type=code&scope=api%20offline_access&" +
"state=" + state + "&code_challenge=" + codeChallenge + "&" +

View File

@@ -60,7 +60,7 @@
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"
@@ -98,7 +98,7 @@
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding ToggleConfirmPasswordCommand}"

View File

@@ -8,6 +8,7 @@ using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using System.Windows.Input;
using Bit.Core;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -71,7 +72,7 @@ namespace Bit.App.Pages
public Command SubmitCommand { get; }
public Command TogglePasswordCommand { get; }
public Command ToggleConfirmPasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string Name { get; set; }
public string Email { get; set; }
public string MasterPassword { get; set; }

View File

@@ -99,7 +99,7 @@
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"
@@ -137,7 +137,7 @@
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding ToggleConfirmPasswordCommand}"

View File

@@ -11,6 +11,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Bit.Core;
using Bit.Core.Models.Domain;
using Xamarin.Essentials;
using Xamarin.Forms;
@@ -85,7 +86,7 @@ namespace Bit.App.Pages
public Command SubmitCommand { get; }
public Command TogglePasswordCommand { get; }
public Command ToggleConfirmPasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string MasterPassword { get; set; }
public string ConfirmMasterPassword { get; set; }
public string Hint { get; set; }

View File

@@ -328,7 +328,7 @@ namespace Bit.App.Pages
AppResources.Cancel, null, options.ToArray());
if (method == AppResources.RecoveryCodeTitle)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/lost-two-step-device/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/lost-two-step-device/");
}
else if (method != AppResources.Cancel && method != null)
{

View File

@@ -97,7 +97,7 @@
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"
@@ -132,7 +132,7 @@
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding ToggleConfirmPasswordCommand}"

View File

@@ -0,0 +1,99 @@
<?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.Accounts.VerificationCodePage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:controls="clr-namespace:Bit.App.Controls"
x:DataType="pages:VerificationCodeViewModel"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:VerificationCodeViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<u:InverseBoolConverter x:Key="inverseBool" />
<Style TargetType="Label" x:Key="lblDescription">
<Setter Property="FontSize" Value="{OnPlatform Android=Large, iOS=Small}" />
</Style>
</ContentPage.Resources>
<ContentPage.Content>
<ScrollView>
<Grid
RowSpacing="10"
ColumnSpacing="10"
RowDefinitions="Auto, Auto, Auto"
ColumnDefinitions="*, *"
Padding="10">
<Label
Grid.Row="0"
Grid.ColumnSpan="2"
Padding="0,10"
Text="{Binding SendCodeStatus}"
StyleClass="box-label"
LineBreakMode="WordWrap"
Margin="0,0,0,10" />
<Grid
StyleClass="box-row"
Grid.Row="1"
Grid.ColumnSpan="2"
RowDefinitions="Auto,Auto,Auto"
ColumnDefinitions="*,Auto"
Padding="0">
<Label
Text="{u:I18n VerificationCode}"
StyleClass="box-label"
Grid.Row="0"
Grid.ColumnSpan="2" />
<controls:MonoEntry
x:Name="_secret"
Text="{Binding Secret}"
StyleClass="box-value"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
IsPassword="{Binding ShowPassword, Converter={StaticResource inverseBool}}"
Grid.Row="1"
Grid.Column="0"
ReturnType="Go"
ReturnCommand="{Binding MainActionCommand}" />
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"
Grid.Row="1"
Grid.Column="1"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ToggleVisibility}"/>
<Label
Text="{u:I18n ConfirmYourIdentity}"
StyleClass="box-footer-label"
LineBreakMode="WordWrap"
Grid.Row="2"
Margin="0,10,0,0" />
</Grid>
<Button
x:Name="_mainActionButton"
Grid.Row="2"
Padding="10,0"
Text="{Binding MainActionText}"
Command="{Binding MainActionCommand}"
HorizontalOptions="FillAndExpand"
VerticalOptions="Start" />
<Button
Grid.Row="2"
Grid.Column="1"
Text="{u:I18n ResendCode}"
Padding="10,0"
Command="{Binding RequestOTPCommand}"
HorizontalOptions="Fill"
VerticalOptions="Start"/>
</Grid>
</ScrollView>
</ContentPage.Content>
</pages:BaseContentPage>

View File

@@ -0,0 +1,49 @@
using System;
using System.Runtime.CompilerServices;
namespace Bit.App.Pages.Accounts
{
public partial class VerificationCodePage : BaseContentPage
{
VerificationCodeViewModel _vm;
public VerificationCodePage(string mainActionText, bool mainActionStyleDanger)
{
InitializeComponent();
_vm = BindingContext as VerificationCodeViewModel;
_vm.Page = this;
_vm.MainActionText = mainActionText;
_mainActionButton.StyleClass = new[]
{
mainActionStyleDanger ? "btn-danger" : "btn-primary"
};
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(VerificationCodeViewModel.ShowPassword))
{
RequestFocus(_secret);
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
await _vm.InitAsync();
RequestFocus(_secret);
}
private async void Close_Clicked(object sender, EventArgs e)
{
if (DoOnce())
{
await Navigation.PopModalAsync();
}
}
}
}

View File

@@ -0,0 +1,181 @@
using System;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System.Threading.Tasks;
using Bit.Core.Exceptions;
using Xamarin.Forms;
using Xamarin.CommunityToolkit.ObjectModel;
using System.Windows.Input;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Enums;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
namespace Bit.App.Pages
{
public class VerificationCodeViewModel : BaseViewModel
{
private readonly IDeviceActionService _deviceActionService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IUserVerificationService _userVerificationService;
private readonly IApiService _apiService;
private readonly IVerificationActionsFlowHelper _verificationActionsFlowHelper;
private bool _showPassword;
private string _secret, _mainActionText, _sendCodeStatus;
public VerificationCodeViewModel()
{
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_userVerificationService = ServiceContainer.Resolve<IUserVerificationService>("userVerificationService");
_apiService = ServiceContainer.Resolve<IApiService>("apiService");
_verificationActionsFlowHelper = ServiceContainer.Resolve<IVerificationActionsFlowHelper>("verificationActionsFlowHelper");
PageTitle = AppResources.VerificationCode;
TogglePasswordCommand = new Command(TogglePassword);
MainActionCommand = new AsyncCommand(MainActionAsync, allowsMultipleExecutions: false);
RequestOTPCommand = new AsyncCommand(RequestOTPAsync, allowsMultipleExecutions: false);
}
public bool ShowPassword
{
get => _showPassword;
set => SetProperty(ref _showPassword, value,
additionalPropertyNames: new string[] { nameof(ShowPasswordIcon) });
}
public string Secret
{
get => _secret;
set => SetProperty(ref _secret, value);
}
public string MainActionText
{
get => _mainActionText;
set => SetProperty(ref _mainActionText, value);
}
public string SendCodeStatus
{
get => _sendCodeStatus;
set => SetProperty(ref _sendCodeStatus, value);
}
public ICommand TogglePasswordCommand { get; }
public ICommand MainActionCommand { get; }
public ICommand RequestOTPCommand { get; }
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public void TogglePassword() => ShowPassword = !ShowPassword;
public async Task InitAsync()
{
await RequestOTPAsync();
}
public async Task RequestOTPAsync()
{
try
{
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
AppResources.InternetConnectionRequiredTitle, AppResources.Ok);
SendCodeStatus = AppResources.AnErrorOccurredWhileSendingAVerificationCodeToYourEmailPleaseTryAgain;
return;
}
await _deviceActionService.ShowLoadingAsync(AppResources.SendingCode);
await _apiService.PostAccountRequestOTP();
await _deviceActionService.HideLoadingAsync();
SendCodeStatus = AppResources.AVerificationCodeWasSentToYourEmail;
_platformUtilsService.ShowToast(null, null, AppResources.CodeSent);
}
catch (ApiException e)
{
await _deviceActionService.HideLoadingAsync();
SendCodeStatus = AppResources.AnErrorOccurredWhileSendingAVerificationCodeToYourEmailPleaseTryAgain;
if (e?.Error != null)
{
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(), AppResources.AnErrorHasOccurred);
}
}
catch (Exception ex)
{
#if !FDROID
Crashes.TrackError(ex);
#endif
await _deviceActionService.HideLoadingAsync();
SendCodeStatus = AppResources.AnErrorOccurredWhileSendingAVerificationCodeToYourEmailPleaseTryAgain;
}
}
private async Task MainActionAsync()
{
try
{
if (string.IsNullOrWhiteSpace(Secret))
{
await _platformUtilsService.ShowDialogAsync(AppResources.EnterTheVerificationCodeThatWasSentToYourEmail, AppResources.AnErrorHasOccurred);
return;
}
if (Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
AppResources.InternetConnectionRequiredTitle, AppResources.Ok);
return;
}
await _deviceActionService.ShowLoadingAsync(AppResources.Verifying);
if (!await _userVerificationService.VerifyUser(Secret, VerificationType.OTP))
{
await _deviceActionService.HideLoadingAsync();
return;
}
await _deviceActionService.HideLoadingAsync();
var parameters = _verificationActionsFlowHelper.GetParameters();
parameters.Secret = Secret;
parameters.VerificationType = VerificationType.OTP;
await _verificationActionsFlowHelper.ExecuteAsync(parameters);
Secret = string.Empty;
}
catch (ApiException e)
{
await _deviceActionService.HideLoadingAsync();
if (e?.Error != null)
{
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(),
AppResources.AnErrorHasOccurred);
}
}
catch (Exception ex)
{
#if !FDROID
Crashes.TrackError(ex);
#endif
await _deviceActionService.HideLoadingAsync();
}
}
}
}

View File

@@ -30,9 +30,17 @@ namespace Bit.App.Pages
public DateTime? LastPageAction { get; set; }
public bool IsThemeDirty { get; set; }
protected override void OnAppearing()
{
base.OnAppearing();
if (IsThemeDirty)
{
UpdateOnThemeChanged();
}
SaveActivity();
}
@@ -123,5 +131,11 @@ namespace Bit.App.Pages
SetServices();
_storageService.SaveAsync(Constants.LastActiveTimeKey, _deviceActionService.GetActiveTime());
}
public virtual Task UpdateOnThemeChanged()
{
IsThemeDirty = false;
return Task.CompletedTask;
}
}
}

View File

@@ -7,6 +7,7 @@
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:domain="clr-namespace:Bit.Core.Models.Domain;assembly=BitwardenCore"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:GeneratorHistoryPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -75,9 +76,9 @@
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
<controls:FaButton
<controls:IconButton
StyleClass="list-row-button, list-row-button-platform"
Text="&#xf0ea;"
Text="{Binding Source={x:Static core:BitwardenIcons.Paste}}"
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"

View File

@@ -1,10 +1,12 @@
using Bit.App.Resources;
using System;
using System;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Styles;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class GeneratorHistoryPage : BaseContentPage
public partial class GeneratorHistoryPage : BaseContentPage, IThemeDirtablePage
{
private GeneratorHistoryPageViewModel _vm;
@@ -28,6 +30,7 @@ namespace Bit.App.Pages
protected override async void OnAppearing()
{
base.OnAppearing();
await LoadOnAppearedAsync(_mainLayout, true, async () => {
await _vm.InitAsync();
});
@@ -59,5 +62,12 @@ namespace Bit.App.Pages
await _vm.ClearAsync();
}
}
public override async Task UpdateOnThemeChanged()
{
await base.UpdateOnThemeChanged();
await _vm?.UpdateOnThemeChanged();
}
}
}

View File

@@ -1,9 +1,12 @@
using Bit.App.Resources;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using System.Collections.Generic;
using System.Threading.Tasks;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -19,8 +22,7 @@ namespace Bit.App.Pages
public GeneratorHistoryPageViewModel()
{
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
"passwordGenerationService");
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>("passwordGenerationService");
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
PageTitle = AppResources.PasswordHistory;
@@ -57,5 +59,21 @@ namespace Bit.App.Pages
_platformUtilsService.ShowToast("info", null,
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
}
public async Task UpdateOnThemeChanged()
{
try
{
await Device.InvokeOnMainThreadAsync(() => History.ResetWithRange(new List<GeneratedPasswordHistory>()));
await InitAsync();
}
catch (System.Exception ex)
{
#if !FDROID
Crashes.TrackError(ex);
#endif
}
}
}
}

View File

@@ -63,6 +63,7 @@
</Frame>
</Grid>
<controls:MonoLabel
x:Name="lblPassword"
StyleClass="text-lg, text-html"
Text="{Binding ColoredPassword, Mode=OneWay}"
Margin="0, 20"

View File

@@ -1,15 +1,15 @@
using Bit.App.Resources;
using System;
using System;
using System.Threading.Tasks;
using Bit.App.Resources;
using Bit.App.Styles;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
namespace Bit.App.Pages
{
public partial class GeneratorPage : BaseContentPage
public partial class GeneratorPage : BaseContentPage, IThemeDirtablePage
{
private readonly IBroadcasterService _broadcasterService;
@@ -49,7 +49,7 @@ namespace Bit.App.Pages
}
if (isIos)
{
_typePicker.On<iOS>().SetUpdateMode(UpdateMode.WhenFinished);
_typePicker.On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUpdateMode(UpdateMode.WhenFinished);
}
}
@@ -61,18 +61,19 @@ namespace Bit.App.Pages
protected async override void OnAppearing()
{
base.OnAppearing();
lblPassword.IsVisible = true;
if (!_fromTabPage)
{
await InitAsync();
}
_broadcasterService.Subscribe(nameof(GeneratorPage), async (message) =>
_broadcasterService.Subscribe(nameof(GeneratorPage), (message) =>
{
if (message.Command == "updatedTheme")
{
Device.BeginInvokeOnMainThread(() =>
{
_vm.RedrawPassword();
});
Device.BeginInvokeOnMainThread(() => _vm.RedrawPassword());
}
});
}
@@ -80,6 +81,9 @@ namespace Bit.App.Pages
protected override void OnDisappearing()
{
base.OnDisappearing();
lblPassword.IsVisible = false;
_broadcasterService.Unsubscribe(nameof(GeneratorPage));
}
@@ -141,5 +145,12 @@ namespace Bit.App.Pages
await Navigation.PopModalAsync();
}
}
public override async Task UpdateOnThemeChanged()
{
await base.UpdateOnThemeChanged();
await Device.InvokeOnMainThreadAsync(() => _vm?.RedrawPassword());
}
}
}

View File

@@ -8,6 +8,7 @@
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:behaviors="clr-namespace:Bit.App.Behaviors"
xmlns:effects="clr-namespace:Bit.App.Effects"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:SendAddEditPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -234,9 +235,10 @@
Margin="10,0,0,0" />
</StackLayout>
</StackLayout>
<StackLayout StyleClass="box-row, box-row-switch">
<StackLayout
StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n ShareOnSave}"
Text="{Binding ShareOnSaveText}"
StyleClass="box-label-regular"
VerticalOptions="Center"
HorizontalOptions="StartAndExpand" />
@@ -255,16 +257,16 @@
StyleClass="box-row-button"
TextColor="{DynamicResource PrimaryColor}"
Margin="0" />
<controls:FaButton
<controls:IconButton
x:Name="_btnOptionsUp"
Text="&#xf077;"
Text="{Binding Source={x:Static core:BitwardenIcons.ChevronUp}}"
StyleClass="box-row-button"
TextColor="{DynamicResource PrimaryColor}"
Clicked="ToggleOptions_Clicked"
IsVisible="False" />
<controls:FaButton
<controls:IconButton
x:Name="_btnOptionsDown"
Text="&#xf078;"
Text="{Binding Source={x:Static core:BitwardenIcons.AngleDown}}"
StyleClass="box-row-button"
TextColor="{DynamicResource PrimaryColor}"
Clicked="ToggleOptions_Clicked"
@@ -428,7 +430,7 @@
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
HorizontalOptions="FillAndExpand" />
<controls:FaButton
<controls:IconButton
IsEnabled="{Binding SendEnabled}"
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"

View File

@@ -7,6 +7,9 @@ using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
using Xamarin.Forms;
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
@@ -22,6 +25,9 @@ namespace Bit.App.Pages
private AppOptions _appOptions;
private SendAddEditPageViewModel _vm;
public Action OnClose { get; set; }
public Action AfterSubmit { get; set; }
public SendAddEditPage(
AppOptions appOptions = null,
string sendId = null,
@@ -82,42 +88,66 @@ namespace Bit.App.Pages
protected override async void OnAppearing()
{
base.OnAppearing();
if (!await AppHelpers.IsVaultTimeoutImmediateAsync())
try
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
}
if (await _vaultTimeoutService.IsLockedAsync())
{
return;
}
await _vm.InitAsync();
_broadcasterService.Subscribe(nameof(SendAddEditPage), message =>
{
if (message.Command == "selectFileResult")
if (!await AppHelpers.IsVaultTimeoutImmediateAsync())
{
Device.BeginInvokeOnMainThread(() =>
{
var data = message.Data as Tuple<byte[], string>;
_vm.FileData = data.Item1;
_vm.FileName = data.Item2;
});
await _vaultTimeoutService.CheckVaultTimeoutAsync();
}
});
await LoadOnAppearedAsync(_scrollView, true, async () =>
{
var success = await _vm.LoadAsync();
if (!success)
if (await _vaultTimeoutService.IsLockedAsync())
{
await Navigation.PopModalAsync();
return;
}
await HandleCreateRequest();
if (!_vm.EditMode && string.IsNullOrWhiteSpace(_vm.Send?.Name))
await _vm.InitAsync();
_broadcasterService.Subscribe(nameof(SendAddEditPage), message =>
{
RequestFocus(_nameEntry);
}
AdjustToolbar();
});
if (message.Command == "selectFileResult")
{
Device.BeginInvokeOnMainThread(() =>
{
var data = message.Data as Tuple<byte[], string>;
_vm.FileData = data.Item1;
_vm.FileName = data.Item2;
});
}
});
await LoadOnAppearedAsync(_scrollView, true, async () =>
{
var success = await _vm.LoadAsync();
if (!success)
{
await CloseAsync();
return;
}
await HandleCreateRequest();
if (!_vm.EditMode && string.IsNullOrWhiteSpace(_vm.Send?.Name))
{
RequestFocus(_nameEntry);
}
AdjustToolbar();
});
}
catch (Exception ex)
{
#if !FDROID
Crashes.TrackError(ex);
#endif
await CloseAsync();
}
}
private async Task CloseAsync()
{
if (OnClose is null)
{
await Navigation.PopModalAsync();
}
else
{
OnClose();
}
}
protected override bool OnBackButtonPressed()
@@ -200,7 +230,11 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
await _vm.SubmitAsync();
var submitted = await _vm.SubmitAsync();
if (submitted)
{
AfterSubmit?.Invoke();
}
}
}
@@ -234,7 +268,7 @@ namespace Bit.App.Pages
{
if (await _vm.DeleteAsync())
{
await Navigation.PopModalAsync();
await CloseAsync();
}
}
}
@@ -274,7 +308,7 @@ namespace Bit.App.Pages
{
if (await _vm.DeleteAsync())
{
await Navigation.PopModalAsync();
await CloseAsync();
}
}
}
@@ -283,7 +317,7 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
await Navigation.PopModalAsync();
await CloseAsync();
}
}
@@ -306,6 +340,7 @@ namespace Bit.App.Pages
}
_vm.IsAddFromShare = true;
_vm.CopyInsteadOfShareAfterSaving = _appOptions.CopyInsteadOfShareAfterSaving;
var name = _appOptions.CreateSend.Item2;
_vm.Send.Name = name;

View File

@@ -4,11 +4,15 @@ using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
using Xamarin.Essentials;
using Xamarin.Forms;
@@ -45,6 +49,7 @@ namespace Bit.App.Pages
};
private bool _disableHideEmail;
private bool _sendOptionsPolicyInEffect;
private bool _copyInsteadOfShareAfterSaving;
public SendAddEditPageViewModel()
{
@@ -96,6 +101,7 @@ namespace Bit.App.Pages
public bool ShareOnSave { get; set; }
public bool DisableHideEmailControl { get; set; }
public bool IsAddFromShare { get; set; }
public string ShareOnSaveText => CopyInsteadOfShareAfterSaving ? AppResources.CopySendLinkOnSave : AppResources.ShareOnSave;
public List<KeyValuePair<string, SendType>> TypeOptions { get; }
public List<KeyValuePair<string, string>> DeletionTypeOptions { get; }
public List<KeyValuePair<string, string>> ExpirationTypeOptions { get; }
@@ -174,6 +180,15 @@ namespace Bit.App.Pages
}
}
}
public bool CopyInsteadOfShareAfterSaving
{
get => _copyInsteadOfShareAfterSaving;
set
{
SetProperty(ref _copyInsteadOfShareAfterSaving, value);
TriggerPropertyChanged(nameof(ShareOnSaveText));
}
}
public SendView Send
{
get => _send;
@@ -215,7 +230,7 @@ namespace Bit.App.Pages
public bool IsFile => Send?.Type == SendType.File;
public bool ShowDeletionCustomPickers => EditMode || DeletionDateTypeSelectedIndex == 6;
public bool ShowExpirationCustomPickers => EditMode || ExpirationDateTypeSelectedIndex == 7;
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public async Task InitAsync()
{
@@ -396,25 +411,36 @@ namespace Bit.App.Pages
EditMode ? AppResources.SendUpdated : AppResources.NewSendCreated);
}
if (IsAddFromShare && Device.RuntimePlatform == Device.Android)
if (!CopyInsteadOfShareAfterSaving)
{
_deviceActionService.CloseMainApp();
await CloseAsync();
}
else
{
await Page.Navigation.PopModalAsync();
}
if (ShareOnSave)
{
var savedSend = await _sendService.GetAsync(sendId);
if (savedSend != null)
{
var savedSendView = await savedSend.DecryptAsync();
await AppHelpers.ShareSendUrlAsync(savedSendView);
if (CopyInsteadOfShareAfterSaving)
{
await AppHelpers.CopySendUrlAsync(savedSendView);
// wait so that the user sees the message before the view gets dismissed
await Task.Delay(1300);
}
else
{
await AppHelpers.ShareSendUrlAsync(savedSendView);
}
}
}
if (CopyInsteadOfShareAfterSaving)
{
await CloseAsync();
}
return true;
}
catch (ApiException e)
@@ -426,9 +452,37 @@ namespace Bit.App.Pages
AppResources.AnErrorHasOccurred);
}
}
catch (Exception ex)
{
await _deviceActionService.HideLoadingAsync();
#if !FDROID
Crashes.TrackError(ex);
#endif
await _platformUtilsService.ShowDialogAsync(AppResources.AnErrorHasOccurred);
}
return false;
}
private async Task CloseAsync()
{
if (IsAddFromShare)
{
if (Device.RuntimePlatform == Device.Android)
{
_deviceActionService.CloseMainApp();
return;
}
if (Page is SendAddEditPage sendPage && sendPage.OnClose != null)
{
sendPage.OnClose();
return;
}
}
await Page.Navigation.PopModalAsync();
}
public async Task<bool> RemovePasswordAsync()
{
return await AppHelpers.RemoveSendPasswordAsync(SendId);
@@ -454,14 +508,7 @@ namespace Bit.App.Pages
if (!SendEnabled)
{
await _platformUtilsService.ShowDialogAsync(AppResources.SendDisabledWarning);
if (IsAddFromShare && Device.RuntimePlatform == Device.Android)
{
_deviceActionService.CloseMainApp();
}
else
{
await Page.Navigation.PopModalAsync();
}
await CloseAsync();
return;
}
if (Send != null)

View File

@@ -0,0 +1,6 @@
namespace Bit.App.Pages
{
public interface ISendGroupingsPageListItem
{
}
}

View File

@@ -51,14 +51,14 @@
x:DataType="pages:SendGroupingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform">
<controls:FaLabel.Effects>
<controls:IconLabel.Effects>
<effects:FixedSizeEffect />
</controls:FaLabel.Effects>
</controls:FaLabel>
</controls:IconLabel.Effects>
</controls:IconLabel>
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
@@ -72,7 +72,29 @@
</controls:ExtendedStackLayout>
</DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:SendGroupingsPageHeaderListItem">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView
StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
<pages:SendGroupingsPageListItemSelector x:Key="sendListItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
SendTemplate="{StaticResource sendTemplate}"
GroupTemplate="{StaticResource sendGroupTemplate}" />
@@ -113,33 +135,9 @@
ItemsSource="{Binding GroupedSends}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:SendGroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform"
IsVisible="{Binding First, Converter={StaticResource inverseBool}}" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView
StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
StyleClass="list, list-platform" />
</RefreshView>
</StackLayout>
</ResourceDictionary>

View File

@@ -0,0 +1,14 @@
namespace Bit.App.Pages
{
public class SendGroupingsPageHeaderListItem : ISendGroupingsPageListItem
{
public SendGroupingsPageHeaderListItem(string title, string itemCount)
{
Title = title;
ItemCount = itemCount;
}
public string Title { get; }
public string ItemCount { get; }
}
}

View File

@@ -1,10 +1,11 @@
using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Enums;
using Bit.Core.Models.View;
namespace Bit.App.Pages
{
public class SendGroupingsPageListItem
public class SendGroupingsPageListItem : ISendGroupingsPageListItem
{
private string _icon;
private string _name;
@@ -53,10 +54,10 @@ namespace Bit.App.Pages
switch (Type.Value)
{
case SendType.Text:
_icon = "\uf0f6"; // fa-file-text-o
_icon = BitwardenIcons.FileText;
break;
case SendType.File:
_icon = "\uf016"; // fa-file-o
_icon = BitwardenIcons.File;
break;
default:
break;

View File

@@ -4,11 +4,17 @@ namespace Bit.App.Pages
{
public class SendGroupingsPageListItemSelector : DataTemplateSelector
{
public DataTemplate HeaderTemplate { get; set; }
public DataTemplate SendTemplate { get; set; }
public DataTemplate GroupTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is SendGroupingsPageHeaderListItem)
{
return HeaderTemplate;
}
if (item is SendGroupingsPageListItem listItem)
{
return listItem.Send != null ? SendTemplate : GroupTemplate;

View File

@@ -10,6 +10,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Essentials;
using Xamarin.Forms;
using DeviceType = Bit.Core.Enums.DeviceType;
@@ -50,7 +51,7 @@ namespace Bit.App.Pages
Loading = true;
PageTitle = AppResources.Send;
GroupedSends = new ExtendedObservableCollection<SendGroupingsPageListGroup>();
GroupedSends = new ObservableRangeCollection<ISendGroupingsPageListItem>();
RefreshCommand = new Command(async () =>
{
Refreshing = true;
@@ -105,7 +106,7 @@ namespace Bit.App.Pages
get => _showList;
set => SetProperty(ref _showList, value);
}
public ExtendedObservableCollection<SendGroupingsPageListGroup> GroupedSends { get; set; }
public ObservableRangeCollection<ISendGroupingsPageListItem> GroupedSends { get; set; }
public Command RefreshCommand { get; set; }
public Command<SendView> SendOptionsCommand { get; set; }
public bool LoadedOnce { get; set; }
@@ -177,7 +178,49 @@ namespace Bit.App.Pages
MainPage ? AppResources.AllSends : AppResources.Sends, sendsListItems.Count,
uppercaseGroupNames, !MainPage));
}
GroupedSends.ResetWithRange(groupedSends);
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android
||
GroupedSends.Any())
{
var items = new List<ISendGroupingsPageListItem>();
foreach (var itemGroup in groupedSends)
{
items.Add(new SendGroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
items.AddRange(itemGroup);
}
GroupedSends.ReplaceRange(items);
}
else
{
// HACK: we need this on iOS, so that it doesn't crash when adding coming from an empty list
var first = true;
var items = new List<ISendGroupingsPageListItem>();
foreach (var itemGroup in groupedSends)
{
if (!first)
{
items.Add(new SendGroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
}
else
{
first = false;
}
items.AddRange(itemGroup);
}
if (groupedSends.Any())
{
GroupedSends.ReplaceRange(new List<ISendGroupingsPageListItem> { new SendGroupingsPageHeaderListItem(groupedSends[0].Name, groupedSends[0].ItemCount) });
GroupedSends.AddRange(items);
}
else
{
GroupedSends.Clear();
}
}
}
finally
{

View File

@@ -7,6 +7,7 @@
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:SendsPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -46,8 +47,8 @@
</ContentPage.Resources>
<StackLayout x:Name="_mainLayout" Spacing="0" Padding="0">
<controls:FaLabel IsVisible="{Binding ShowSearchDirection}"
Text="&#xf002;"
<controls:IconLabel IsVisible="{Binding ShowSearchDirection}"
Text="{Binding Source={x:Static core:BitwardenIcons.Search}}"
StyleClass="text-muted"
FontSize="50"
VerticalOptions="CenterAndExpand"

View File

@@ -97,7 +97,7 @@
Grid.Column="0"
ReturnType="Go"
ReturnCommand="{Binding ExportVaultCommand}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"

View File

@@ -8,6 +8,7 @@ using System.Text;
using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
@@ -138,7 +139,7 @@ namespace Bit.App.Pages
public Command TogglePasswordCommand { get; }
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public void TogglePassword()
{

View File

@@ -0,0 +1,6 @@
namespace Bit.App.Pages
{
public interface ISettingsPageListItem
{
}
}

View File

@@ -45,20 +45,65 @@
VerticalOptions="CenterAndExpand"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub" />
<TimePicker IsVisible="{Binding ShowTimeInput}"
Time="{Binding Time}" Format="HH:mm"
</controls:ExtendedStackLayout>
</DataTemplate>
<DataTemplate
x:Key="timePickerTemplate"
x:DataType="pages:SettingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<Frame
IsVisible="{Binding UseFrame}"
Padding="10"
HasShadow="False"
BackgroundColor="Transparent"
BorderColor="Accent">
<Label
Text="{Binding Name, Mode=OneWay}"
StyleClass="text-muted, text-sm, text-bold"
HorizontalTextAlignment="Center" />
</Frame>
<Label IsVisible="{Binding UseFrame, Converter={StaticResource inverseBool}}"
Text="{Binding Name, Mode=OneWay}"
LineBreakMode="{Binding LineBreakMode}"
HorizontalOptions="StartAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<TimePicker Time="{Binding Time}" Format="HH:mm"
PropertyChanged="OnTimePickerPropertyChanged"
HorizontalOptions="End"
VerticalOptions="Center"
FontSize="Small"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub" Margin="-5" />
StyleClass="list-sub" Margin="-5"/>
<controls:ExtendedStackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="ActivateTimePicker"/>
</controls:ExtendedStackLayout.GestureRecognizers>
</controls:ExtendedStackLayout>
</DataTemplate>
</DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:SettingsPageHeaderListItem">
<StackLayout
Padding="0" Spacing="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
<pages:SettingsPageListItemSelector
x:Key="listItemDataTemplateSelector"
RegularTemplate="{StaticResource regularTemplate}" />
HeaderTemplate="{StaticResource headerTemplate}"
RegularTemplate="{StaticResource regularTemplate}"
TimePickerTemplate="{StaticResource timePickerTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
@@ -66,28 +111,8 @@
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:SettingsPageListGroup">
<StackLayout
Padding="0" Spacing="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform"
IsVisible="{Binding First, Converter={StaticResource inverseBool}}" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
StyleClass="list, list-platform" />
</pages:BaseContentPage>

View File

@@ -1,4 +1,5 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Abstractions;
@@ -45,6 +46,17 @@ namespace Bit.App.Pages
return base.OnBackButtonPressed();
}
void ActivateTimePicker(object sender, EventArgs args)
{
var stackLayout = (ExtendedStackLayout)sender;
SettingsPageListItem item = (SettingsPageListItem)stackLayout.BindingContext;
if (item.ShowTimeInput)
{
var timePicker = stackLayout.Children.Where(x => x is TimePicker).FirstOrDefault();
((TimePicker)timePicker)?.Focus();
}
}
async void OnTimePickerPropertyChanged(object sender, PropertyChangedEventArgs args)
{
var s = (TimePicker) sender;

View File

@@ -0,0 +1,12 @@
namespace Bit.App.Pages
{
public class SettingsPageHeaderListItem : ISettingsPageListItem
{
public SettingsPageHeaderListItem(string title)
{
Title = title;
}
public string Title { get; }
}
}

View File

@@ -1,12 +1,11 @@
using System;
using Bit.App.Resources;
using Bit.App.Utilities;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class SettingsPageListItem
public class SettingsPageListItem : ISettingsPageListItem
{
public string Icon { get; set; }
public string Name { get; set; }

View File

@@ -4,13 +4,19 @@ namespace Bit.App.Pages
{
public class SettingsPageListItemSelector : DataTemplateSelector
{
public DataTemplate HeaderTemplate { get; set; }
public DataTemplate RegularTemplate { get; set; }
public DataTemplate TimePickerTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is SettingsPageHeaderListItem)
{
return HeaderTemplate;
}
if (item is SettingsPageListItem listItem)
{
return RegularTemplate;
return listItem.ShowTimeInput ? TimePickerTemplate : RegularTemplate;
}
return null;
}

View File

@@ -10,6 +10,8 @@ using System.Threading.Tasks;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
using Xamarin.Forms;
using ZXing.Client.Result;
using Xamarin.CommunityToolkit.ObjectModel;
namespace Bit.App.Pages
{
@@ -81,11 +83,11 @@ namespace Bit.App.Pages
_keyConnectorService = ServiceContainer.Resolve<IKeyConnectorService>("keyConnectorService");
_clipboardService = ServiceContainer.Resolve<IClipboardService>("clipboardService");
GroupedItems = new ExtendedObservableCollection<SettingsPageListGroup>();
GroupedItems = new ObservableRangeCollection<ISettingsPageListItem>();
PageTitle = AppResources.Settings;
}
public ExtendedObservableCollection<SettingsPageListGroup> GroupedItems { get; set; }
public ObservableRangeCollection<ISettingsPageListItem> GroupedItems { get; set; }
public async Task InitAsync()
{
@@ -132,7 +134,20 @@ namespace Bit.App.Pages
{
var debugText = string.Format("{0}: {1} ({2})", AppResources.Version,
_platformUtilsService.GetApplicationVersion(), _deviceActionService.GetBuildNumber());
#if DEBUG
var pushNotificationsRegistered = ServiceContainer.Resolve<IPushNotificationService>("pushNotificationService").IsRegisteredForPush;
var pnServerRegDate = await _storageService.GetAsync<DateTime>(Constants.PushLastRegistrationDateKey);
var pnServerError = await _storageService.GetAsync<string>(Constants.PushInstallationRegistrationError);
var pnServerRegDateMessage = default(DateTime) == pnServerRegDate ? "-" : $"{pnServerRegDate.ToShortDateString()}-{pnServerRegDate.ToShortTimeString()} UTC";
var errorMessage = string.IsNullOrEmpty(pnServerError) ? string.Empty : $"Push Notifications Server Registration error: {pnServerError}";
var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}\nPush Notifications registered:{2}\nPush Notifications Server Last Date :{3}\n{4}", DateTime.Now.Year, debugText, pushNotificationsRegistered, pnServerRegDateMessage, errorMessage);
#else
var text = string.Format("© Bitwarden Inc. 2015-{0}\n\n{1}", DateTime.Now.Year, debugText);
#endif
var copy = await _platformUtilsService.ShowDialogAsync(text, AppResources.Bitwarden, AppResources.Copy,
AppResources.Close);
if (copy)
@@ -143,7 +158,7 @@ namespace Bit.App.Pages
public void Help()
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/");
}
public async Task FingerprintAsync()
@@ -163,7 +178,7 @@ namespace Bit.App.Pages
AppResources.LearnMore, AppResources.Close);
if (learnMore)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/fingerprint-phrase/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/fingerprint-phrase/");
}
}
@@ -174,7 +189,7 @@ namespace Bit.App.Pages
public void Import()
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/import-data/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/import-data/");
}
public void WebVault()
@@ -193,7 +208,7 @@ namespace Bit.App.Pages
AppResources.LearnOrg, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/what-is-an-organization/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/about-organizations/");
}
}
@@ -203,7 +218,7 @@ namespace Bit.App.Pages
AppResources.TwoStepLogin, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/setup-two-step-login/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/setup-two-step-login/");
}
}
@@ -213,7 +228,7 @@ namespace Bit.App.Pages
AppResources.ChangeMasterPassword, AppResources.Yes, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/change-your-master-password/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/master-password/#change-your-master-password");
}
}
@@ -495,7 +510,9 @@ namespace Bit.App.Pages
new SettingsPageListItem { Name = AppResources.RateTheApp },
new SettingsPageListItem { Name = AppResources.DeleteAccount }
};
GroupedItems.ResetWithRange(new List<SettingsPageListGroup>
// TODO: improve this. Leaving this as is to reduce error possibility on the hotfix.
var settingsListGroupItems = new List<SettingsPageListGroup>()
{
new SettingsPageListGroup(autofillItems, AppResources.Autofill, doUpper, true),
new SettingsPageListGroup(manageItems, AppResources.Manage, doUpper),
@@ -503,7 +520,50 @@ namespace Bit.App.Pages
new SettingsPageListGroup(accountItems, AppResources.Account, doUpper),
new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper),
new SettingsPageListGroup(otherItems, AppResources.Other, doUpper)
});
};
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android
||
GroupedItems.Any())
{
var items = new List<ISettingsPageListItem>();
foreach (var itemGroup in settingsListGroupItems)
{
items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
items.AddRange(itemGroup);
}
GroupedItems.ReplaceRange(items);
}
else
{
// HACK: we need this on iOS, so that it doesn't crash when adding coming from an empty list
var first = true;
var items = new List<ISettingsPageListItem>();
foreach (var itemGroup in settingsListGroupItems)
{
if (!first)
{
items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
}
else
{
first = false;
}
items.AddRange(itemGroup);
}
if (settingsListGroupItems.Any())
{
GroupedItems.ReplaceRange(new List<ISettingsPageListItem> { new SettingsPageHeaderListItem(settingsListGroupItems[0].Name) });
GroupedItems.AddRange(items);
}
else
{
GroupedItems.Clear();
}
}
}
private bool IncludeLinksWithSubscriptionInfo()

View File

@@ -31,14 +31,14 @@ namespace Bit.App.Pages
_sendGroupingsPage = new NavigationPage(new SendGroupingsPage(true, null, null, appOptions))
{
Title = AppResources.Send,
IconImageSource = "paper_plane.png",
IconImageSource = "send.png",
};
Children.Add(_sendGroupingsPage);
_generatorPage = new NavigationPage(new GeneratorPage(true, null, this))
{
Title = AppResources.Generator,
IconImageSource = "refresh.png"
IconImageSource = "generate.png"
};
Children.Add(_generatorPage);

View File

@@ -9,6 +9,7 @@
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
xmlns:behaviors="clr-namespace:Bit.App.Behaviors"
xmlns:effects="clr-namespace:Bit.App.Effects"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:AddEditPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -142,9 +143,9 @@
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False"
IsEnabled="{Binding Cipher.ViewPassword}"/>
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf058;"
Text="{Binding Source={x:Static core:BitwardenIcons.CheckCircle}}"
Command="{Binding CheckPasswordCommand}"
Grid.Row="0"
Grid.Column="1"
@@ -152,7 +153,7 @@
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CheckPassword}"
IsVisible="{Binding Cipher.ViewPassword}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowPasswordIcon}"
Command="{Binding TogglePasswordCommand}"
@@ -162,9 +163,9 @@
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ToggleVisibility}"
IsVisible="{Binding Cipher.ViewPassword}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf021;"
Text="{Binding Source={x:Static core:BitwardenIcons.Generate}}"
Command="{Binding GeneratePasswordCommand}"
Grid.Row="0"
Grid.Column="3"
@@ -199,9 +200,9 @@
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="{Binding TotpColumnSpan}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf030;"
Text="{Binding Source={x:Static core:BitwardenIcons.Camera}}"
Clicked="ScanTotp_Clicked"
Grid.Row="0"
Grid.Column="1"
@@ -244,7 +245,7 @@
IsPassword="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowCardNumberIcon}"
Command="{Binding ToggleCardNumberCommand}"
@@ -308,7 +309,7 @@
IsPassword="{Binding ShowCardCode, Converter={StaticResource inverseBool}}"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowCardCodeIcon}"
Command="{Binding ToggleCardCodeCommand}"
@@ -514,9 +515,9 @@
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf013;"
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
Command="{Binding BindingContext.UriOptionsCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
@@ -560,9 +561,9 @@
<Label
Text="{u:I18n PasswordPrompt}"
StyleClass="box-label-regular" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf29c;"
Text="{Binding Source={x:Static core:BitwardenIcons.QuestionCircle}}"
Command="{Binding PasswordPromptHelpCommand}"
TextColor="{DynamicResource MutedColor}"
AutomationProperties.IsInAccessibleTree="True"
@@ -672,7 +673,7 @@
Grid.Column="1"
Grid.RowSpan="2"
IsVisible="{Binding IsBooleanType}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowHiddenValueIcon}"
Command="{Binding ToggleHiddenValueCommand}"
@@ -682,9 +683,9 @@
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf013;"
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
Command="{Binding BindingContext.FieldOptionsCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"

View File

@@ -11,8 +11,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Controls;
using Bit.Core;
using Xamarin.Forms;
using View = Xamarin.Forms.View;
#if !FDROID
using Microsoft.AppCenter.Crashes;
#endif
namespace Bit.App.Pages
{
@@ -287,9 +290,9 @@ namespace Bit.App.Pages
public bool IsSecureNote => Cipher?.Type == CipherType.SecureNote;
public bool ShowUris => IsLogin && Cipher.Login.HasUris;
public bool ShowAttachments => Cipher.HasAttachments;
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowCardNumberIcon => ShowCardNumber ? "" : "";
public string ShowCardCodeIcon => ShowCardCode ? "" : "";
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string ShowCardNumberIcon => ShowCardNumber ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string ShowCardCodeIcon => ShowCardCode ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public int PasswordFieldColSpan => Cipher.ViewPassword ? 1 : 4;
public int TotpColumnSpan => Cipher.ViewPassword ? 1 : 2;
public bool AllowPersonal { get; set; }
@@ -493,9 +496,12 @@ namespace Bit.App.Pages
try
{
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
await _cipherService.SaveWithServerAsync(cipher);
Cipher.Id = cipher.Id;
await _deviceActionService.HideLoadingAsync();
_platformUtilsService.ShowToast("success", null,
EditMode && !CloneMode ? AppResources.ItemUpdated : AppResources.NewItemCreated);
_messagingService.Send(EditMode && !CloneMode ? "editedCipher" : "addedCipher", Cipher.Id);
@@ -511,19 +517,30 @@ namespace Bit.App.Pages
{
ViewPage?.UpdateCipherId(this.Cipher.Id);
}
await Page.Navigation.PopModalAsync();
// if the app is tombstoned then PopModalAsync would throw index out of bounds
if (Page.Navigation?.ModalStack?.Count > 0)
{
await Page.Navigation.PopModalAsync();
}
}
return true;
}
catch (ApiException e)
catch (ApiException apiEx)
{
await _deviceActionService.HideLoadingAsync();
if (e?.Error != null)
if (apiEx?.Error != null)
{
await _platformUtilsService.ShowDialogAsync(e.Error.GetSingleMessage(),
await _platformUtilsService.ShowDialogAsync(apiEx.Error.GetSingleMessage(),
AppResources.AnErrorHasOccurred);
}
}
catch(Exception genex)
{
#if !FDROID
Crashes.TrackError(genex);
#endif
await _deviceActionService.HideLoadingAsync();
}
return false;
}
@@ -742,7 +759,7 @@ namespace Bit.App.Pages
public void PasswordPromptHelp()
{
_platformUtilsService.LaunchUri("https://bitwarden.com/help/article/managing-items/#protect-individual-items");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/managing-items/#protect-individual-items");
}
private void TypeChanged()
@@ -936,7 +953,7 @@ namespace Bit.App.Pages
public Command ToggleHiddenValueCommand { get; set; }
public string ShowHiddenValueIcon => _showHiddenValue ? "" : "";
public string ShowHiddenValueIcon => _showHiddenValue ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public bool IsTextType => _field.Type == FieldType.Text;
public bool IsBooleanType => _field.Type == FieldType.Boolean;
public bool IsHiddenType => _field.Type == FieldType.Hidden;

View File

@@ -7,6 +7,7 @@
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:AttachmentsPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -49,9 +50,9 @@
StyleClass="box-sub-label"
HorizontalTextAlignment="End"
VerticalTextAlignment="Center" />
<controls:FaButton
<controls:IconButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf014;"
Text="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
Command="{Binding BindingContext.DeleteAttachmentCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
VerticalOptions="Center"

View File

@@ -18,6 +18,7 @@ namespace Bit.App.Pages
private readonly ICipherService _cipherService;
private readonly ICryptoService _cryptoService;
private readonly IUserService _userService;
private readonly IVaultTimeoutService _timeoutService;
private readonly IPlatformUtilsService _platformUtilsService;
private CipherView _cipher;
private Cipher _cipherDomain;
@@ -33,6 +34,7 @@ namespace Bit.App.Pages
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_userService = ServiceContainer.Resolve<IUserService>("userService");
_timeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
Attachments = new ExtendedObservableCollection<AttachmentView>();
DeleteAttachmentCommand = new Command<AttachmentView>(DeleteAsync);
PageTitle = AppResources.Attachments;
@@ -76,7 +78,7 @@ namespace Bit.App.Pages
AppResources.FeatureUnavailable, AppResources.LearnMore, AppResources.Cancel);
if (confirmed)
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/update-encryption-key/");
_platformUtilsService.LaunchUri("https://bitwarden.com/help/account-encryption-key/#rotate-your-encryption-key");
}
}
}
@@ -135,6 +137,11 @@ namespace Bit.App.Pages
public async Task ChooseFileAsync()
{
// Prevent Android from locking if vault timeout set to "immediate"
if (Device.RuntimePlatform == Device.Android)
{
_timeoutService.DelayLockAndLogoutMs = 60000;
}
await _deviceActionService.SelectFileAsync();
}

View File

@@ -29,8 +29,28 @@
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}"
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}" />
</DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:GroupingsPageHeaderListItem">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
</StackLayout>
</DataTemplate>
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
CipherTemplate="{StaticResource cipherTemplate}" />
<StackLayout x:Key="mainLayout" x:Name="_mainLayout">
@@ -52,30 +72,9 @@
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
StyleClass="list, list-platform" />
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -38,14 +39,14 @@ namespace Bit.App.Pages
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
GroupedItems = new ExtendedObservableCollection<GroupingsPageListGroup>();
GroupedItems = new ObservableRangeCollection<IGroupingsPageListItem>();
CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync);
}
public string Name { get; set; }
public string Uri { get; set; }
public Command CipherOptionsCommand { get; set; }
public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; }
public ObservableRangeCollection<IGroupingsPageListItem> GroupedItems { get; set; }
public bool ShowList
{
@@ -108,7 +109,49 @@ namespace Bit.App.Pages
new GroupingsPageListGroup(fuzzy, AppResources.PossibleMatchingItems, fuzzy.Count, false,
!hasMatching));
}
GroupedItems.ResetWithRange(groupedItems);
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android
||
GroupedItems.Any())
{
var items = new List<IGroupingsPageListItem>();
foreach (var itemGroup in groupedItems)
{
items.Add(new GroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
items.AddRange(itemGroup);
}
GroupedItems.ReplaceRange(items);
}
else
{
// HACK: we need this on iOS, so that it doesn't crash when adding coming from an empty list
var first = true;
var items = new List<IGroupingsPageListItem>();
foreach (var itemGroup in groupedItems)
{
if (!first)
{
items.Add(new GroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
}
else
{
first = false;
}
items.AddRange(itemGroup);
}
if (groupedItems.Any())
{
GroupedItems.ReplaceRange(new List<IGroupingsPageListItem> { new GroupingsPageHeaderListItem(groupedItems[0].Name, groupedItems[0].ItemCount) });
GroupedItems.AddRange(items);
}
else
{
GroupedItems.Clear();
}
}
ShowList = groupedItems.Any();
}

View File

@@ -7,6 +7,7 @@
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:views="clr-namespace:Bit.Core.Models.View;assembly=BitwardenCore"
xmlns:core="clr-namespace:Bit.Core;assembly=BitwardenCore"
x:DataType="pages:CiphersPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
@@ -46,8 +47,8 @@
</ContentPage.Resources>
<StackLayout x:Name="_mainLayout" Spacing="0" Padding="0">
<controls:FaLabel IsVisible="{Binding ShowSearchDirection}"
Text="&#xf002;"
<controls:IconLabel IsVisible="{Binding ShowSearchDirection}"
Text="{Binding Source={x:Static core:BitwardenIcons.Search}}"
StyleClass="text-muted"
FontSize="50"
VerticalOptions="CenterAndExpand"

View File

@@ -46,29 +46,52 @@
<DataTemplate x:Key="groupTemplate"
x:DataType="pages:GroupingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
StyleClass="list-row, list-row-platform">
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform">
<controls:FaLabel.Effects>
<controls:IconLabel.Effects>
<effects:FixedSizeEffect />
</controls:FaLabel.Effects>
</controls:FaLabel>
</controls:IconLabel.Effects>
</controls:IconLabel>
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub"/>
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub"/>
</controls:ExtendedStackLayout>
</DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:GroupingsPageHeaderListItem">
<StackLayout
Spacing="0"
Padding="0"
VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
CipherTemplate="{StaticResource cipherTemplate}"
GroupTemplate="{StaticResource groupTemplate}" />
@@ -95,32 +118,9 @@
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform"
IsVisible="{Binding First, Converter={StaticResource inverseBool}}" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
StyleClass="list, list-platform" />
</RefreshView>
</StackLayout>
</ResourceDictionary>

View File

@@ -0,0 +1,14 @@
namespace Bit.App.Pages
{
public class GroupingsPageHeaderListItem : IGroupingsPageListItem
{
public GroupingsPageHeaderListItem(string title, string itemCount)
{
Title = title;
ItemCount = itemCount;
}
public string Title { get; }
public string ItemCount { get; set; }
}
}

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