mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
Compare commits
62 Commits
tech-debt/
...
v2.16.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea28fd462d | ||
|
|
14b6ccca6d | ||
|
|
4202a90674 | ||
|
|
ad55ba232f | ||
|
|
1f8620dc17 | ||
|
|
a4bc46f408 | ||
|
|
62f1522af3 | ||
|
|
3d0a405d7d | ||
|
|
bb18e40d00 | ||
|
|
6305b4d292 | ||
|
|
3562e2bac6 | ||
|
|
403f78ceca | ||
|
|
e4e52a41e0 | ||
|
|
4fb811ae87 | ||
|
|
2e1de95461 | ||
|
|
3127295444 | ||
|
|
52f1143ad7 | ||
|
|
615136be96 | ||
|
|
e4230ac4f6 | ||
|
|
15e9915da6 | ||
|
|
59ed76d956 | ||
|
|
972755c725 | ||
|
|
92c40e2984 | ||
|
|
56de47960d | ||
|
|
9eed421c67 | ||
|
|
9b17392e06 | ||
|
|
15db96b06c | ||
|
|
54ccc1cbca | ||
|
|
6bed326f28 | ||
|
|
ee69364b1d | ||
|
|
76f1057951 | ||
|
|
3491c1aaeb | ||
|
|
427ff09af0 | ||
|
|
6453836866 | ||
|
|
10fafaf8c8 | ||
|
|
31cdf401f1 | ||
|
|
0068674bac | ||
|
|
4373cee636 | ||
|
|
63b27f4e6d | ||
|
|
fba5ecf304 | ||
|
|
a183861b87 | ||
|
|
d0ffb108b1 | ||
|
|
c0c893fd59 | ||
|
|
5f29fc8f89 | ||
|
|
f8a7eb4c94 | ||
|
|
ef6184a05b | ||
|
|
37f4439892 | ||
|
|
f1ccbbc105 | ||
|
|
74e90da662 | ||
|
|
939db8ebe0 | ||
|
|
4e7ceaf5b5 | ||
|
|
5a6aec51f3 | ||
|
|
137c762e40 | ||
|
|
3f1674c1f1 | ||
|
|
52024109f7 | ||
|
|
6f3999016f | ||
|
|
2791d4b8ec | ||
|
|
42403210a0 | ||
|
|
5e15a2f30e | ||
|
|
c6547771a5 | ||
|
|
9fdcba386e | ||
|
|
86397a6f1e |
@@ -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>
|
||||
|
||||
BIN
.github/secrets/dist_autofill.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_autofill.mobileprovision.gpg
vendored
Binary file not shown.
BIN
.github/secrets/dist_bitwarden.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_bitwarden.mobileprovision.gpg
vendored
Binary file not shown.
BIN
.github/secrets/dist_extension.mobileprovision.gpg
vendored
BIN
.github/secrets/dist_extension.mobileprovision.gpg
vendored
Binary file not shown.
BIN
.github/secrets/dist_share_extension.mobileprovision.gpg
vendored
Normal file
BIN
.github/secrets/dist_share_extension.mobileprovision.gpg
vendored
Normal file
Binary file not shown.
BIN
.github/secrets/iphone-distribution-cert.p12.gpg
vendored
BIN
.github/secrets/iphone-distribution-cert.p12.gpg
vendored
Binary file not shown.
BIN
.github/secrets/play_creds.json.gpg
vendored
BIN
.github/secrets/play_creds.json.gpg
vendored
Binary file not shown.
79
.github/workflows/build.yml
vendored
79
.github/workflows/build.yml
vendored
@@ -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 }}
|
||||
|
||||
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
@@ -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 }}
|
||||
|
||||
18
.github/workflows/version-bump.yml
vendored
18
.github/workflows/version-bump.yml
vendored
@@ -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 }}"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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.
BIN
src/Android/Assets/bwi-font.ttf
Normal file
BIN
src/Android/Assets/bwi-font.ttf
Normal file
Binary file not shown.
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
9
src/Android/Resources/drawable/generate.xml
Normal file
9
src/Android/Resources/drawable/generate.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
9
src/Android/Resources/drawable/send.xml
Normal file
9
src/Android/Resources/drawable/send.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
27
src/Android/Resources/layout/progress_dialog_layout.xml
Normal file
27
src/Android/Resources/layout/progress_dialog_layout.xml
Normal 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>
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace Bit.App.Abstractions
|
||||
{
|
||||
public interface IPushNotificationService
|
||||
{
|
||||
bool IsRegisteredForPush { get; }
|
||||
Task<string> GetTokenAsync();
|
||||
Task RegisterAsync();
|
||||
Task UnregisterAsync();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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=""
|
||||
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=""
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Paperclip}}"
|
||||
IsVisible="{Binding Cipher.HasAttachments, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n Attachments}" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
|
||||
IsVisible="{Binding Send.PendingDelete, Mode=OneTime}"
|
||||
AutomationProperties.IsInAccessibleTree="True"
|
||||
AutomationProperties.Name="{u:I18n PendingDelete}" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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=""
|
||||
<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"
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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 + "&" +
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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}"
|
||||
|
||||
99
src/App/Pages/Accounts/VerificationCodePage.xaml
Normal file
99
src/App/Pages/Accounts/VerificationCodePage.xaml
Normal 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>
|
||||
49
src/App/Pages/Accounts/VerificationCodePage.xaml.cs
Normal file
49
src/App/Pages/Accounts/VerificationCodePage.xaml.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
181
src/App/Pages/Accounts/VerificationCodeViewModel.cs
Normal file
181
src/App/Pages/Accounts/VerificationCodeViewModel.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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=""
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Paste}}"
|
||||
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
Grid.Row="0"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
</Frame>
|
||||
</Grid>
|
||||
<controls:MonoLabel
|
||||
x:Name="lblPassword"
|
||||
StyleClass="text-lg, text-html"
|
||||
Text="{Binding ColoredPassword, Mode=OneWay}"
|
||||
Margin="0, 20"
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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=""
|
||||
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=""
|
||||
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}"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public interface ISendGroupingsPageListItem
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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=""
|
||||
<controls:IconLabel IsVisible="{Binding ShowSearchDirection}"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Search}}"
|
||||
StyleClass="text-muted"
|
||||
FontSize="50"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
|
||||
@@ -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}"
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public interface ISettingsPageListItem
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public class SettingsPageHeaderListItem : ISettingsPageListItem
|
||||
{
|
||||
public SettingsPageHeaderListItem(string title)
|
||||
{
|
||||
Title = title;
|
||||
}
|
||||
|
||||
public string Title { get; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
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=""
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Cog}}"
|
||||
Command="{Binding BindingContext.FieldOptionsCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
Grid.Row="0"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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=""
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Trash}}"
|
||||
Command="{Binding BindingContext.DeleteAttachmentCommand, Source={x:Reference _page}}"
|
||||
CommandParameter="{Binding .}"
|
||||
VerticalOptions="Center"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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=""
|
||||
<controls:IconLabel IsVisible="{Binding ShowSearchDirection}"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.Search}}"
|
||||
StyleClass="text-muted"
|
||||
FontSize="50"
|
||||
VerticalOptions="CenterAndExpand"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user