1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-02 08:33:17 +00:00

Compare commits

..

49 Commits

Author SHA1 Message Date
Matt Portune
10a718b0c7 bump version to 2.11.2 (#1473) 2021-07-23 11:33:53 -04:00
Thomas Rittson
9ec4050e4d Move remaining primary buttons in login flow (#1470)
* Fix show/hide logic on Continue button

* Fix bug in 2FA method selection modal

* Move Log In button in SSO flow

* Fix linting
2021-07-22 07:56:39 +10:00
Matt Portune
93e2c0df7c keep app version at 2.11.1 for now (#1471) 2021-07-21 14:03:38 -04:00
Matt Portune
8d07397a59 Revert "lib updates and app version bump (#1468)" (#1469)
This reverts commit 15d44b873b.
2021-07-20 16:21:41 -04:00
Matt Portune
15d44b873b lib updates and app version bump (#1468)
* lib updates and app version bump

* added explicit androidx core dependency
2021-07-20 12:57:01 -04:00
Sang
6a979d0ff5 2FA screen: move continue to a button (#1427)
* Move continue to a button

* Resolve pr comments

* Move use another two step method button

* Resolve code suggestions

* Resolve for iPhone

* Apply suggestions from code review

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>

Co-authored-by: Thomas Rittson <31796059+eliykat@users.noreply.github.com>
2021-07-20 14:50:45 +10:00
Matt Portune
a4db088eda bugfix for incorrect type and nullable for some org vars (#1465) 2021-07-16 13:57:15 -04:00
Matt Portune
96454b7cbf add toggle for removing links to pages containing subscription info (#1463) 2021-07-16 12:02:00 -04:00
Matt Portune
9c1df2179c bump version to 2.11.1 (#1462) 2021-07-14 14:46:18 -04:00
Matt Portune
52c9125404 bump version to 2.11.0 (#1461) 2021-07-13 12:52:14 -04:00
Matt Portune
172a857604 handle intent exceptions to prevent denial of service (#1458) 2021-07-12 12:31:39 -04:00
Matt Portune
d8e68a266c bugfixes for lock block when setting timeout to immediate (#1455) 2021-07-12 10:58:17 -04:00
Matt Portune
1f57ba6c50 workaround for off-screen draw bug in XF4.5+ part 2 (#1454) 2021-07-09 17:29:57 -04:00
Matt Portune
ff19578807 Fix for password unlock for autofill and share-to-send on Android (#1453) 2021-07-09 11:48:03 -04:00
Matt Portune
9298d57f22 fix for resuming autofill when back button was previously used to exit (#1451) 2021-07-06 11:10:17 -04:00
Martin Choutka
8cf5d5728e MaximumAccessCountInfo locale string update (#1441)
String MaximumAccessCountInfo doesn't have "Send" with a capital "s".
2021-07-02 12:20:40 -04:00
Matt Portune
bdf6d764ca update csv lib and skip link (#1449) 2021-07-02 11:21:36 -04:00
Matt Portune
05e8da4bcc Workaround for off-screen draw bug in XF4.5+ (#1447)
* workaround for off-screen draw bug in xf4.5+

* check cols even if orgId is present
2021-06-30 17:46:59 -04:00
Matt Portune
382e547f74 fix for export password handling (#1448) 2021-06-30 16:05:30 -04:00
Kyle Spearrin
4f9985d2b0 New Crowdin updates (#1444)
* New translations AppResources.resx (Romanian)

* New translations copy.resx (Bosnian)

* New translations copy.resx (Kannada)

* New translations copy.resx (Tamil)

* New translations copy.resx (Tamil)

* New translations copy.resx (Bosnian)

* New translations copy.resx (Kannada)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Serbian (Cyrillic))

* New translations AppResources.resx (Slovenian)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Bengali)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Afrikaans)

* New translations AppResources.resx (Belarusian)

* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Catalan)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Greek)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Hebrew)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Tamil)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Sinhala)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Latvian)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (Malayalam)

* New translations AppResources.resx (Bosnian)

* New translations AppResources.resx (Kannada)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (English, India)

* New translations copy.resx (Bosnian)

* New translations copy.resx (German)

* New translations copy.resx (Danish)

* New translations copy.resx (Czech)

* New translations copy.resx (Catalan)

* New translations copy.resx (Bulgarian)

* New translations copy.resx (Belarusian)

* New translations copy.resx (Afrikaans)

* New translations copy.resx (Spanish)

* New translations copy.resx (French)

* New translations copy.resx (Romanian)

* New translations copy.resx (English, India)

* New translations copy.resx (Norwegian Bokmal)

* New translations copy.resx (Kannada)

* New translations copy.resx (Sinhala)

* New translations copy.resx (Malayalam)

* New translations copy.resx (Finnish)

* New translations copy.resx (Persian)

* New translations copy.resx (Ukrainian)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Tamil)

* New translations copy.resx (English, United Kingdom)

* New translations copy.resx (Bengali)

* New translations copy.resx (Thai)

* New translations copy.resx (Croatian)

* New translations copy.resx (Estonian)

* New translations copy.resx (Latvian)

* New translations copy.resx (Hindi)

* New translations copy.resx (Greek)

* New translations copy.resx (Hebrew)

* New translations copy.resx (Swedish)

* New translations copy.resx (Latvian)

* New translations copy.resx (Persian)

* New translations copy.resx (Tamil)

* New translations copy.resx (Bengali)

* New translations copy.resx (Thai)

* New translations copy.resx (Croatian)

* New translations copy.resx (Estonian)

* New translations copy.resx (Hindi)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (English, United Kingdom)

* New translations copy.resx (Malayalam)

* New translations copy.resx (Bosnian)

* New translations copy.resx (Sinhala)

* New translations copy.resx (Kannada)

* New translations copy.resx (Norwegian Bokmal)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Russian)

* New translations copy.resx (Italian)

* New translations copy.resx (Japanese)

* New translations copy.resx (Korean)

* New translations copy.resx (Dutch)

* New translations copy.resx (Polish)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Slovak)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Slovenian)

* New translations copy.resx (Serbian (Cyrillic))

* New translations copy.resx (Swedish)

* New translations copy.resx (Turkish)

* New translations copy.resx (Ukrainian)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Turkish)

* New translations copy.resx (Serbian (Cyrillic))

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Slovenian)

* New translations copy.resx (Italian)

* New translations copy.resx (Danish)

* New translations copy.resx (German)

* New translations copy.resx (Greek)

* New translations copy.resx (Finnish)

* New translations copy.resx (Hebrew)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Japanese)

* New translations copy.resx (Catalan)

* New translations copy.resx (Korean)

* New translations copy.resx (Dutch)

* New translations copy.resx (Polish)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Russian)

* New translations copy.resx (Slovak)

* New translations copy.resx (Czech)

* New translations copy.resx (Bulgarian)

* New translations copy.resx (Belarusian)

* New translations copy.resx (Romanian)

* New translations copy.resx (French)

* New translations copy.resx (Spanish)

* New translations copy.resx (Afrikaans)

* New translations copy.resx (English, India)
2021-06-29 15:41:27 -04:00
Matt Portune
ef97417cd7 disable send tests (#1443) 2021-06-29 15:29:10 -04:00
Chad Scharf
7bdf4d8b18 Fix encoding of & in resx XML (#1445) 2021-06-29 14:32:07 -04:00
Matt Portune
a6c95d06b5 fix for vault timeout locking issue on android (#1442) 2021-06-29 10:23:20 -04:00
Matt Gibson
bd4a275558 Revert "Redefine cipher "share" to "move to organization" (#1433)" (#1440)
This reverts commit 2003ac9d2c.
2021-06-24 14:33:19 -05:00
Oscar Hinton
a2b46ee7cb Add help link to password reprompt (#1439) 2021-06-24 17:26:47 +02:00
Matt Gibson
2003ac9d2c Redefine cipher "share" to "move to organization" (#1433) 2021-06-18 06:52:01 -05:00
Oscar Hinton
2a5667251e Add a 250ms sleep before prompting for password (#1431) 2021-06-15 20:29:11 +02:00
Thomas Rittson
79589b07fc Use 2 iterations for local password hashing (#1423)
* Add HashPurpose parameter to HashPasswordAsync

* Use 2 iterations for local password hashing

* Force logout if user has old keyHash stored

* Revert "Force logout if user has old keyHash stored"

This reverts commit 497d4928fa.

* Add backwards compatability with existing keyHash
2021-06-15 07:39:34 +10:00
Oscar Hinton
0aed13a2cf Fix selecting ciphers in search not working (#1426) 2021-06-11 15:20:42 +02:00
Oscar Hinton
df412e75d1 More Autofill fixes (#1425) 2021-06-11 15:20:21 +02:00
Oscar Hinton
2b8dbde923 Fixes for password reprompt (#1416) 2021-06-10 17:57:18 +02:00
Matt Portune
33791a03ac track failed unlock attempts in storage (#1421) 2021-06-09 10:03:05 -04:00
Matt Gibson
80a33e98a2 Use type to ensure transmitted data is encrypted (#1422) 2021-06-09 08:45:30 -05:00
Trey Greer
afed18908b Asset update (#1417)
* updated screenshots and copy for iOS + Android

* fixed data for copy file

* fixed data for copy file for Google

* fixed more file formatting items for resx

* added Google video
2021-06-01 10:16:52 -04:00
Thomas Rittson
fe58dea3e0 Add encKeyValidation string to encrypted exports (#1412) 2021-05-29 06:16:19 +10:00
Kyle Spearrin
569045fcd5 add auth-email header to auth request (#1414) 2021-05-28 14:06:42 -04:00
Matt Portune
fdda670311 replaced blank taskaffinity with singletask launchmode (#1410) 2021-05-26 14:18:01 -04:00
CookieJarApps
fbb7b05b9c Added support for SmartCookieWeb and SmartCookieWeb Preview (#1411) 2021-05-26 13:41:16 -04:00
Oscar Hinton
976eeab6d7 Password reprompt (#1365)
* Make card number hidden

* Add support for password reprompt

* Rename PasswordPrompt to Reprompt

* Protect autofill

* Use Enums.CipherRepromptType

* Fix iOS not building

* Protect iOS autofill

* Update to match jslib

* Fix failing build
2021-05-21 15:13:54 +02:00
Matt Portune
e61bcd2785 fix for activity exporting and workaround for task affinity (#1408) 2021-05-19 15:55:16 -04:00
Captain Trips
570edb4319 fixes bitwarden/mobile#967 (#1067) 2021-05-17 15:38:21 -04:00
Vince Grassia
8fe8c42765 Pin versions of actions in workflow (#1405) 2021-05-17 15:15:08 -04:00
Matt Gibson
0eebe6b156 Encode exports as UTF8 (#1404) 2021-05-17 11:40:20 -05:00
Matt Portune
946831b37e version bumps (#1399) 2021-05-13 15:21:24 -04:00
Matt Portune
1d4e742d66 Forms update with CollectionView conversion (#1374)
* Forms update with CollectionView conversion

* updates

* removed unnecessary import
2021-05-13 14:36:20 -04:00
Matt Portune
29979f6b04 expand package visibility for Android 11+ (#1384) 2021-05-13 14:16:53 -04:00
Matt Portune
2f6e1ff477 lib updates (#1381)
* lib updates

* included csv and biometric lib
2021-05-13 14:15:26 -04:00
Thomas Rittson
c1030c48fa Explain how to verify email for file Sends (#1395)
* Explain how to verify email for file Sends

* Revert "Explain how to verify email for file Sends"

This reverts commit b72314bc93.

* Explain how to verify email for file Sends
2021-05-11 17:52:18 -04:00
Kyle Spearrin
ef5d08cb75 New Crowdin updates (#1397)
* New translations AppResources.resx (Romanian)

* New translations copy.resx (Tamil)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Chinese Simplified)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Persian)

* New translations AppResources.resx (Tamil)

* New translations copy.resx (Tamil)

* New translations AppResources.resx (Bengali)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Estonian)

* New translations AppResources.resx (Latvian)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (English, United Kingdom)

* New translations AppResources.resx (Malayalam)

* New translations AppResources.resx (Sinhala)

* New translations AppResources.resx (Norwegian Bokmal)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Serbian (Cyrillic))

* New translations AppResources.resx (French)

* New translations AppResources.resx (Greek)

* New translations AppResources.resx (Spanish)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Afrikaans)

* New translations AppResources.resx (Belarusian)

* New translations AppResources.resx (Bulgarian)

* New translations AppResources.resx (Catalan)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Danish)

* New translations AppResources.resx (German)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Slovenian)

* New translations AppResources.resx (Hebrew)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Korean)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (English, India)
2021-05-11 14:03:24 -04:00
397 changed files with 11332 additions and 2914 deletions

View File

@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout repo
uses: actions/checkout@v2
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
- name: Set up cloc
run: |
@@ -31,22 +31,21 @@ jobs:
steps:
- name: Set up MSBuild
uses: microsoft/setup-msbuild@v1
uses: microsoft/setup-msbuild@c26a08ba26249b81327e26f6ef381897b6a8754d
- name: Print environment
run: |
nuget help
nuget help | grep Version
msbuild -version
dotnet --info
Write-Output "GitHub ref: $env:GITHUB_REF"
Write-Output "GitHub event: $env:GITHUB_EVENT"
shell: pwsh
echo "GitHub ref: $GITHUB_REF"
echo "GitHub event: $GITHUB_EVENT"
env:
GITHUB_REF: ${{ github.ref }}
GITHUB_EVENT: ${{ github.event_name }}
- name: Checkout repo
uses: actions/checkout@v2
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
- name: Decrypt secrets
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
@@ -83,14 +82,14 @@ jobs:
- name: Upload Play Store .aab artifact
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with:
name: com.x8bit.bitwarden.aab
path: ./com.x8bit.bitwarden.aab
- name: Upload Play Store .apk artifact
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with:
name: com.x8bit.bitwarden.apk
path: ./com.x8bit.bitwarden.apk
@@ -115,7 +114,7 @@ jobs:
- name: Upload F-Droid .apk artifact
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with:
name: com.x8bit.bitwarden-fdroid.apk
path: ./com.x8bit.bitwarden-fdroid.apk
@@ -146,7 +145,7 @@ jobs:
steps:
- name: Set up Node
if: github.event_name == 'release'
uses: actions/setup-node@v1
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
with:
node-version: '10.x'
@@ -181,7 +180,7 @@ jobs:
- name: Checkout repo
if: github.event_name == 'release'
uses: actions/checkout@v2
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
- name: Install Node dependencies
if: github.event_name == 'release'
@@ -215,18 +214,17 @@ jobs:
steps:
- name: Print environment
run: |
nuget help
nuget help | grep Version
msbuild -version
dotnet --info
Write-Output "GitHub ref: $env:GITHUB_REF"
Write-Output "GitHub event: $env:GITHUB_EVENT"
shell: pwsh
echo "GitHub ref: $GITHUB_REF"
echo "GitHub event: $GITHUB_EVENT"
env:
GITHUB_REF: ${{ github.ref }}
GITHUB_EVENT: ${{ github.event_name }}
- name: Checkout repo
uses: actions/checkout@v2
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
- name: Decrypt secrets
run: ./.github/scripts/ios/decrypt-secrets.ps1
@@ -271,7 +269,7 @@ jobs:
- name: Upload App Store .ipa artifact
if: github.ref == 'refs/heads/master' || github.event_name == 'release'
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700
with:
name: Bitwarden.ipa
path: ./bitwarden-export/Bitwarden.ipa

View File

@@ -46,6 +46,8 @@ namespace Bit.Droid.Accessibility
new Browser("com.chrome.beta", "url_bar"),
new Browser("com.chrome.canary", "url_bar"),
new Browser("com.chrome.dev", "url_bar"),
new Browser("com.cookiegames.smartcookie", "search"),
new Browser("com.cookiejarapps.android.smartcookieweb", "mozac_browser_toolbar_url_view"),
new Browser("com.duckduckgo.mobile.android", "omnibarTextInput"),
new Browser("com.ecosia.android", "url_bar"),
new Browser("com.google.android.apps.chrome", "url_bar"),

View File

@@ -28,7 +28,6 @@
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>3</WarningLevel>
<AndroidLinkMode>None</AndroidLinkMode>
<AndroidSupportedAbis />
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
</PropertyGroup>
@@ -75,24 +74,26 @@
<Version>2.1.0.4</Version>
</PackageReference>
<PackageReference Include="Portable.BouncyCastle">
<Version>1.8.6.7</Version>
<Version>1.8.10</Version>
</PackageReference>
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.3-beta01" />
<PackageReference Include="Xamarin.AndroidX.Core" Version="1.5.0" />
<PackageReference Include="Xamarin.AndroidX.AppCompat.AppCompatResources" Version="1.3.0" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.0" />
<PackageReference Include="Xamarin.AndroidX.AutoFill" Version="1.1.0.6" />
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0.8" />
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0.7" />
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.2.4" />
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.8" />
<PackageReference Include="Xamarin.Essentials">
<Version>1.5.3.2</Version>
<Version>1.7.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Firebase.Messaging">
<Version>121.0.1</Version>
<Version>122.0.0</Version>
</PackageReference>
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.0.0" />
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.1.0" />
<PackageReference Include="Xamarin.AndroidX.Legacy.Support.V4" Version="1.0.0" />
<PackageReference Include="Xamarin.AndroidX.CardView" Version="1.0.0" />
<PackageReference Include="Xamarin.AndroidX.MediaRouter" Version="1.1.0" />
<PackageReference Include="Xamarin.AndroidX.Migration" Version="1.0.6" />
<PackageReference Include="Xamarin.Google.Dagger" Version="2.27.0" />
<PackageReference Include="Xamarin.Google.Android.Material" Version="1.3.0.1" />
<PackageReference Include="Xamarin.Google.Dagger" Version="2.37.0" />
<PackageReference Include="Xamarin.GooglePlayServices.SafetyNet">
<Version>71.1600.0</Version>
<Version>117.0.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
@@ -118,20 +119,18 @@
<Compile Include="Receivers\ClearClipboardAlarmReceiver.cs" />
<Compile Include="Receivers\RestrictionsChangedReceiver.cs" />
<Compile Include="Receivers\EventUploadReceiver.cs" />
<Compile Include="Receivers\LockAlarmReceiver.cs" />
<Compile Include="Receivers\PackageReplacedReceiver.cs" />
<Compile Include="Renderers\CipherViewCellRenderer.cs" />
<Compile Include="Renderers\ExtendedGridRenderer.cs" />
<Compile Include="Renderers\ExtendedDatePickerRenderer.cs" />
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
<Compile Include="Renderers\ExtendedStackLayoutRenderer.cs" />
<Compile Include="Renderers\ExtendedTimePickerRenderer.cs" />
<Compile Include="Renderers\ExtendedSliderRenderer.cs" />
<Compile Include="Renderers\CustomEditorRenderer.cs" />
<Compile Include="Renderers\CustomPickerRenderer.cs" />
<Compile Include="Renderers\CustomEntryRenderer.cs" />
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
<Compile Include="Renderers\ExtendedListViewRenderer.cs" />
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
<Compile Include="Renderers\SendViewCellRenderer.cs" />
<Compile Include="Services\AndroidPushNotificationService.cs" />
<Compile Include="Services\AndroidLogService.cs" />
<Compile Include="MainApplication.cs" />
@@ -173,6 +172,9 @@
<AndroidResource Include="Resources\drawable\ic_launcher_foreground.xml" />
<AndroidResource Include="Resources\drawable\id.xml" />
<AndroidResource Include="Resources\drawable\info.xml" />
<AndroidResource Include="Resources\drawable\list_item_bg.xml" />
<AndroidResource Include="Resources\drawable\list_item_bg_dark.xml" />
<AndroidResource Include="Resources\drawable\list_item_bg_nord.xml" />
<AndroidResource Include="Resources\drawable\lock.xml" />
<AndroidResource Include="Resources\drawable\login.xml" />
<AndroidResource Include="Resources\drawable\logo.xml" />
@@ -185,7 +187,6 @@
<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\layout\SendViewCell.axml" />
<AndroidResource Include="Resources\layout\Tabbar.axml" />
<AndroidResource Include="Resources\layout\Toolbar.axml" />
<AndroidResource Include="Resources\mipmap-anydpi-v26\ic_launcher.xml" />
@@ -262,12 +263,6 @@
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\CipherViewCell.axml">
<Generator>MSBuild:UpdateGeneratedFiles</Generator>
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\app_restrictions.xml">
<Generator>MSBuild:UpdateGeneratedFiles</Generator>

View File

@@ -63,6 +63,8 @@ namespace Bit.Droid.Autofill
"com.chrome.beta",
"com.chrome.canary",
"com.chrome.dev",
"com.cookiegames.smartcookie",
"com.cookiejarapps.android.smartcookieweb",
"com.ecosia.android",
"com.google.android.apps.chrome",
"com.google.android.apps.chrome_dev",
@@ -140,13 +142,14 @@ namespace Bit.Droid.Autofill
{
var allCiphers = ciphers.Item1.ToList();
allCiphers.AddRange(ciphers.Item2.ToList());
return allCiphers.Select(c => new FilledItem(c)).ToList();
var nonPromptCiphers = allCiphers.Where(cipher => cipher.Reprompt == CipherRepromptType.None);
return nonPromptCiphers.Select(c => new FilledItem(c)).ToList();
}
}
else if (parser.FieldCollection.FillableForCard)
{
var ciphers = await cipherService.GetAllDecryptedAsync();
return ciphers.Where(c => c.Type == CipherType.Card).Select(c => new FilledItem(c)).ToList();
return ciphers.Where(c => c.Type == CipherType.Card && c.Reprompt == CipherRepromptType.None).Select(c => new FilledItem(c)).ToList();
}
return new List<FilledItem>();
}

View File

@@ -57,6 +57,7 @@ namespace Bit.Droid.Autofill
}
List<FilledItem> items = null;
await _vaultTimeoutService.CheckVaultTimeoutAsync();
var locked = await _vaultTimeoutService.IsLockedAsync();
if (!locked)
{

View File

@@ -27,6 +27,7 @@ namespace Bit.Droid
Icon = "@mipmap/ic_launcher",
Theme = "@style/LaunchTheme",
MainLauncher = true,
LaunchMode = LaunchMode.SingleTask,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation |
ConfigChanges.Keyboard | ConfigChanges.KeyboardHidden |
ConfigChanges.Navigation)]
@@ -50,7 +51,6 @@ namespace Bit.Droid
private IAppIdService _appIdService;
private IStorageService _storageService;
private IEventService _eventService;
private PendingIntent _vaultTimeoutAlarmPendingIntent;
private PendingIntent _clearClipboardPendingIntent;
private PendingIntent _eventUploadPendingIntent;
private AppOptions _appOptions;
@@ -63,9 +63,6 @@ namespace Bit.Droid
var eventUploadIntent = new Intent(this, typeof(EventUploadReceiver));
_eventUploadPendingIntent = PendingIntent.GetBroadcast(this, 0, eventUploadIntent,
PendingIntentFlags.UpdateCurrent);
var alarmIntent = new Intent(this, typeof(LockAlarmReceiver));
_vaultTimeoutAlarmPendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent,
PendingIntentFlags.UpdateCurrent);
var clearClipboardIntent = new Intent(this, typeof(ClearClipboardAlarmReceiver));
_clearClipboardPendingIntent = PendingIntent.GetBroadcast(this, 0, clearClipboardIntent,
PendingIntentFlags.UpdateCurrent);
@@ -103,20 +100,7 @@ namespace Bit.Droid
_broadcasterService.Subscribe(_activityKey, (message) =>
{
if (message.Command == "scheduleVaultTimeoutTimer")
{
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
var vaultTimeoutMinutes = (int)message.Data;
var vaultTimeoutMs = vaultTimeoutMinutes * 60000;
var triggerMs = Java.Lang.JavaSystem.CurrentTimeMillis() + vaultTimeoutMs + 10;
alarmManager.Set(AlarmType.RtcWakeup, triggerMs, _vaultTimeoutAlarmPendingIntent);
}
else if (message.Command == "cancelVaultTimeoutTimer")
{
var alarmManager = GetSystemService(AlarmService) as AlarmManager;
alarmManager.Cancel(_vaultTimeoutAlarmPendingIntent);
}
else if (message.Command == "startEventTimer")
if (message.Command == "startEventTimer")
{
StartEventAlarm();
}
@@ -171,33 +155,40 @@ namespace Bit.Droid
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
if (intent.GetBooleanExtra("generatorTile", false))
try
{
_messagingService.Send("popAllAndGoToTabGenerator");
if (_appOptions != null)
if (intent.GetBooleanExtra("generatorTile", false))
{
_appOptions.GeneratorTile = true;
_messagingService.Send("popAllAndGoToTabGenerator");
if (_appOptions != null)
{
_appOptions.GeneratorTile = true;
}
}
else if (intent.GetBooleanExtra("myVaultTile", false))
{
_messagingService.Send("popAllAndGoToTabMyVault");
if (_appOptions != null)
{
_appOptions.MyVaultTile = true;
}
}
else if (intent.Action == Intent.ActionSend && intent.Type != null)
{
if (_appOptions != null)
{
_appOptions.CreateSend = GetCreateSendRequest(intent);
}
_messagingService.Send("popAllAndGoToTabSend");
}
else
{
ParseYubiKey(intent.DataString);
}
}
else if (intent.GetBooleanExtra("myVaultTile", false))
catch (Exception e)
{
_messagingService.Send("popAllAndGoToTabMyVault");
if (_appOptions != null)
{
_appOptions.MyVaultTile = true;
}
}
else if (intent.Action == Intent.ActionSend && intent.Type != null)
{
if (_appOptions != null)
{
_appOptions.CreateSend = GetCreateSendRequest(intent);
}
_messagingService.Send("popAllAndGoToTabSend");
}
else
{
ParseYubiKey(intent.DataString);
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", e.GetType(), e.StackTrace);
}
}
@@ -343,6 +334,11 @@ namespace Bit.Droid
{
if (intent.Action == Intent.ActionSend && intent.Type != null)
{
if ((intent.Flags & ActivityFlags.LaunchedFromHistory) == ActivityFlags.LaunchedFromHistory)
{
// don't re-deliver intent if resuming from app switcher
return null;
}
var type = intent.Type;
if (type.Contains("text/"))
{

View File

@@ -99,6 +99,9 @@ namespace Bit.Droid
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
broadcasterService);
var biometricService = new BiometricService();
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(mobileStorageService, secureStorageService, cryptoFunctionService);
var passwordRepromptService = new MobilePasswordRepromptService(platformUtilsService, cryptoService);
ServiceContainer.Register<IBroadcasterService>("broadcasterService", broadcasterService);
ServiceContainer.Register<IMessagingService>("messagingService", messagingService);
@@ -110,6 +113,9 @@ namespace Bit.Droid
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
ServiceContainer.Register<IBiometricService>("biometricService", biometricService);
ServiceContainer.Register<ICryptoFunctionService>("cryptoFunctionService", cryptoFunctionService);
ServiceContainer.Register<ICryptoService>("cryptoService", cryptoService);
ServiceContainer.Register<IPasswordRepromptService>("passwordRepromptService", passwordRepromptService);
// Push
#if FDROID

View File

@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:versionCode="1"
android:versionName="2.10.0"
android:versionName="2.11.2"
android:installLocation="internalOnly"
package="com.x8bit.bitwarden">
@@ -54,12 +54,7 @@
<!-- Package visibility (for Android 11+) -->
<queries>
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="http"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW"/>
<data android:scheme="https"/>
<action android:name="*"/>
</intent>
</queries>

View File

@@ -1,16 +0,0 @@
using Android.Content;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
namespace Bit.Droid.Receivers
{
[BroadcastReceiver(Name = "com.x8bit.bitwarden.LockAlarmReceiver", Exported = false)]
public class LockAlarmReceiver : BroadcastReceiver
{
public async override void OnReceive(Context context, Intent intent)
{
var vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
await vaultTimeoutService.CheckVaultTimeoutAsync();
}
}
}

View File

@@ -1,242 +0,0 @@
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Views.InputMethods;
using Android.Widget;
using Bit.App.Controls;
using Bit.App.Utilities;
using Bit.Droid.Renderers;
using FFImageLoading;
using FFImageLoading.Views;
using FFImageLoading.Work;
using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(CipherViewCell), typeof(CipherViewCellRenderer))]
namespace Bit.Droid.Renderers
{
public class CipherViewCellRenderer : ViewCellRenderer
{
private static Typeface _faTypeface;
private static Typeface _miTypeface;
private static Android.Graphics.Color _textColor;
private static Android.Graphics.Color _mutedColor;
private static Android.Graphics.Color _disabledIconColor;
private static bool _usingLightTheme;
private AndroidCipherCell _cell;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView,
ViewGroup parent, Context context)
{
// TODO expand beyond light/dark detection once we support custom theme switching without app restart
var themeChanged = _usingLightTheme != ThemeManager.UsingLightTheme;
if (_faTypeface == null)
{
_faTypeface = Typeface.CreateFromAsset(context.Assets, "FontAwesome.ttf");
}
if (_miTypeface == null)
{
_miTypeface = Typeface.CreateFromAsset(context.Assets, "MaterialIcons_Regular.ttf");
}
if (_textColor == default(Android.Graphics.Color) || themeChanged)
{
_textColor = ThemeManager.GetResourceColor("TextColor").ToAndroid();
}
if (_mutedColor == default(Android.Graphics.Color) || themeChanged)
{
_mutedColor = ThemeManager.GetResourceColor("MutedColor").ToAndroid();
}
if (_disabledIconColor == default(Android.Graphics.Color) || themeChanged)
{
_disabledIconColor = ThemeManager.GetResourceColor("DisabledIconColor").ToAndroid();
}
_usingLightTheme = ThemeManager.UsingLightTheme;
var cipherCell = item as CipherViewCell;
_cell = convertView as AndroidCipherCell;
if (_cell == null)
{
_cell = new AndroidCipherCell(context, cipherCell, _faTypeface, _miTypeface);
}
else
{
_cell.CipherViewCell.PropertyChanged -= CellPropertyChanged;
}
cipherCell.PropertyChanged += CellPropertyChanged;
_cell.UpdateCell(cipherCell);
_cell.UpdateColors(_textColor, _mutedColor, _disabledIconColor);
return _cell;
}
public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var cipherCell = sender as CipherViewCell;
_cell.CipherViewCell = cipherCell;
if (e.PropertyName == CipherViewCell.CipherProperty.PropertyName)
{
_cell.UpdateCell(cipherCell);
}
else if (e.PropertyName == CipherViewCell.WebsiteIconsEnabledProperty.PropertyName)
{
_cell.UpdateIconImage(cipherCell);
}
}
}
public class AndroidCipherCell : LinearLayout, INativeElementView
{
private readonly Typeface _faTypeface;
private readonly Typeface _miTypeface;
private IScheduledWork _currentTask;
public AndroidCipherCell(Context context, CipherViewCell cipherView, Typeface faTypeface, Typeface miTypeface)
: base(context)
{
CipherViewCell = cipherView;
_faTypeface = faTypeface;
_miTypeface = miTypeface;
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.CipherViewCell, null);
IconImage = view.FindViewById<IconImageView>(Resource.Id.CipherCellIconImage);
Icon = view.FindViewById<TextView>(Resource.Id.CipherCellIcon);
Name = view.FindViewById<TextView>(Resource.Id.CipherCellName);
SubTitle = view.FindViewById<TextView>(Resource.Id.CipherCellSubTitle);
SharedIcon = view.FindViewById<TextView>(Resource.Id.CipherCellSharedIcon);
AttachmentsIcon = view.FindViewById<TextView>(Resource.Id.CipherCellAttachmentsIcon);
MoreButton = view.FindViewById<Android.Widget.Button>(Resource.Id.CipherCellButton);
MoreButton.Click += MoreButton_Click;
Icon.Typeface = _faTypeface;
SharedIcon.Typeface = _faTypeface;
AttachmentsIcon.Typeface = _faTypeface;
MoreButton.Typeface = _miTypeface;
var small = (float)Device.GetNamedSize(NamedSize.Small, typeof(Label));
Icon.SetTextSize(ComplexUnitType.Pt, 10);
Name.SetTextSize(ComplexUnitType.Sp, (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label)));
SubTitle.SetTextSize(ComplexUnitType.Sp, small);
SharedIcon.SetTextSize(ComplexUnitType.Sp, small);
AttachmentsIcon.SetTextSize(ComplexUnitType.Sp, small);
MoreButton.SetTextSize(ComplexUnitType.Sp, 25);
AddView(view);
}
public CipherViewCell CipherViewCell { get; set; }
public Element Element => CipherViewCell;
public IconImageView IconImage { get; set; }
public TextView Icon { get; set; }
public TextView Name { get; set; }
public TextView SubTitle { get; set; }
public TextView SharedIcon { get; set; }
public TextView AttachmentsIcon { get; set; }
public Android.Widget.Button MoreButton { get; set; }
public void UpdateCell(CipherViewCell cipherCell)
{
UpdateIconImage(cipherCell);
var cipher = cipherCell.Cipher;
Name.Text = cipher.Name;
if (!string.IsNullOrWhiteSpace(cipher.SubTitle))
{
SubTitle.Text = cipher.SubTitle;
SubTitle.Visibility = ViewStates.Visible;
}
else
{
SubTitle.Visibility = ViewStates.Invisible;
}
SharedIcon.Visibility = cipher.Shared ? ViewStates.Visible : ViewStates.Gone;
AttachmentsIcon.Visibility = cipher.HasAttachments ? ViewStates.Visible : ViewStates.Gone;
}
public void UpdateIconImage(CipherViewCell cipherCell)
{
if (_currentTask != null && !_currentTask.IsCancelled && !_currentTask.IsCompleted)
{
_currentTask.Cancel();
}
var cipher = cipherCell.Cipher;
var iconImage = cipherCell.GetIconImage(cipher);
if (iconImage.Item2 != null)
{
IconImage.SetImageResource(Resource.Drawable.login);
IconImage.Visibility = ViewStates.Visible;
Icon.Visibility = ViewStates.Gone;
_currentTask = ImageService.Instance.LoadUrl(iconImage.Item2).DownSample(64).Into(IconImage);
IconImage.Key = iconImage.Item2;
}
else
{
IconImage.Visibility = ViewStates.Gone;
Icon.Visibility = ViewStates.Visible;
Icon.Text = iconImage.Item1;
}
}
public void UpdateColors(Android.Graphics.Color textColor, Android.Graphics.Color mutedColor,
Android.Graphics.Color iconDisabledColor)
{
Name.SetTextColor(textColor);
SubTitle.SetTextColor(mutedColor);
Icon.SetTextColor(mutedColor);
SharedIcon.SetTextColor(mutedColor);
AttachmentsIcon.SetTextColor(mutedColor);
MoreButton.SetTextColor(iconDisabledColor);
}
private void MoreButton_Click(object sender, EventArgs e)
{
if (CipherViewCell.ButtonCommand?.CanExecute(CipherViewCell.Cipher) ?? false)
{
CipherViewCell.ButtonCommand.Execute(CipherViewCell.Cipher);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
MoreButton.Click -= MoreButton_Click;
}
base.Dispose(disposing);
}
}
[Android.Runtime.Preserve(AllMembers = true)]
[Register("bit.droid.renderers.IconImageView")]
public class IconImageView : ImageViewAsync
{
public IconImageView(Context context) : base(context)
{ }
public IconImageView(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{ }
public IconImageView(Context context, IAttributeSet attrs)
: base(context, attrs)
{ }
public string Key { get; set; }
protected override void JavaFinalize()
{
SetImageDrawable(null);
SetImageBitmap(null);
ImageService.Instance.InvalidateCacheEntryAsync(Key, FFImageLoading.Cache.CacheType.Memory);
base.JavaFinalize();
}
}
}

View File

@@ -0,0 +1,43 @@
using Android.Content;
using Bit.App.Controls;
using Bit.App.Utilities;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedGrid), typeof(ExtendedGridRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedGridRenderer : ViewRenderer
{
private static int? _bgResId;
public ExtendedGridRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
{
base.OnElementChanged(elementChangedEvent);
if (elementChangedEvent.NewElement != null)
{
SetBackgroundResource(GetBgResId());
}
}
private int GetBgResId()
{
if (_bgResId == null)
{
if (ThemeManager.GetTheme(true) == "nord")
{
_bgResId = Resource.Drawable.list_item_bg_nord;
}
else
{
_bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
Resource.Drawable.list_item_bg_dark;
}
}
return _bgResId.Value;
}
}
}

View File

@@ -1,29 +0,0 @@
using Android.Content;
using Android.Views;
using Bit.App.Controls;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedListView), typeof(ExtendedListViewRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedListViewRenderer : ListViewRenderer
{
public ExtendedListViewRenderer(Context context)
: base(context)
{ }
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (Control != null && e.NewElement != null && e.NewElement is ExtendedListView listView)
{
// Pad for FAB
Control.SetPadding(0, 0, 0, 170);
Control.SetClipToPadding(false);
Control.ScrollBarStyle = ScrollbarStyles.OutsideOverlay;
}
}
}
}

View File

@@ -0,0 +1,43 @@
using Android.Content;
using Bit.App.Controls;
using Bit.App.Utilities;
using Bit.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(ExtendedStackLayout), typeof(ExtendedStackLayoutRenderer))]
namespace Bit.Droid.Renderers
{
public class ExtendedStackLayoutRenderer : ViewRenderer
{
private static int? _bgResId;
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
{
base.OnElementChanged(elementChangedEvent);
if (elementChangedEvent.NewElement != null)
{
SetBackgroundResource(GetBgResId());
}
}
private int GetBgResId()
{
if (_bgResId == null)
{
if (ThemeManager.GetTheme(true) == "nord")
{
_bgResId = Resource.Drawable.list_item_bg_nord;
}
else
{
_bgResId ??= ThemeManager.UsingLightTheme ? Resource.Drawable.list_item_bg :
Resource.Drawable.list_item_bg_dark;
}
}
return _bgResId.Value;
}
}
}

View File

@@ -1,210 +0,0 @@
using System;
using System.ComponentModel;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.Util;
using Android.Views;
using Android.Widget;
using Bit.App.Controls;
using Bit.App.Utilities;
using Bit.Droid.Renderers;
using FFImageLoading.Work;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Button = Android.Widget.Button;
using Color = Android.Graphics.Color;
using View = Android.Views.View;
[assembly: ExportRenderer(typeof(SendViewCell), typeof(SendViewCellRenderer))]
namespace Bit.Droid.Renderers
{
public class SendViewCellRenderer : ViewCellRenderer
{
private static Typeface _faTypeface;
private static Typeface _miTypeface;
private static Color _textColor;
private static Color _mutedColor;
private static Color _disabledIconColor;
private static bool _usingLightTheme;
private AndroidSendCell _cell;
protected override View GetCellCore(Cell item, View convertView,
ViewGroup parent, Context context)
{
// TODO expand beyond light/dark detection once we support custom theme switching without app restart
var themeChanged = _usingLightTheme != ThemeManager.UsingLightTheme;
if (_faTypeface == null)
{
_faTypeface = Typeface.CreateFromAsset(context.Assets, "FontAwesome.ttf");
}
if (_miTypeface == null)
{
_miTypeface = Typeface.CreateFromAsset(context.Assets, "MaterialIcons_Regular.ttf");
}
if (_textColor == default(Color) || themeChanged)
{
_textColor = ThemeManager.GetResourceColor("TextColor").ToAndroid();
}
if (_mutedColor == default(Color) || themeChanged)
{
_mutedColor = ThemeManager.GetResourceColor("MutedColor").ToAndroid();
}
if (_disabledIconColor == default(Color) || themeChanged)
{
_disabledIconColor = ThemeManager.GetResourceColor("DisabledIconColor").ToAndroid();
}
_usingLightTheme = ThemeManager.UsingLightTheme;
var sendCell = item as SendViewCell;
_cell = convertView as AndroidSendCell;
if (_cell == null)
{
_cell = new AndroidSendCell(context, sendCell, _faTypeface, _miTypeface);
}
else
{
_cell.SendViewCell.PropertyChanged -= CellPropertyChanged;
}
sendCell.PropertyChanged += CellPropertyChanged;
_cell.UpdateCell(sendCell);
_cell.UpdateColors(_textColor, _mutedColor, _disabledIconColor);
return _cell;
}
public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var sendCell = sender as SendViewCell;
_cell.SendViewCell = sendCell;
if (e.PropertyName == SendViewCell.SendProperty.PropertyName)
{
_cell.UpdateCell(sendCell);
}
}
}
public class AndroidSendCell : LinearLayout, INativeElementView
{
private readonly Typeface _faTypeface;
private readonly Typeface _miTypeface;
private IScheduledWork _currentTask;
public AndroidSendCell(Context context, SendViewCell sendView, Typeface faTypeface, Typeface miTypeface)
: base(context)
{
SendViewCell = sendView;
_faTypeface = faTypeface;
_miTypeface = miTypeface;
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.SendViewCell, null);
Icon = view.FindViewById<TextView>(Resource.Id.SendCellIcon);
Name = view.FindViewById<TextView>(Resource.Id.SendCellName);
SubTitle = view.FindViewById<TextView>(Resource.Id.SendCellSubTitle);
DisabledIcon = view.FindViewById<TextView>(Resource.Id.SendCellDisabledIcon);
HasPasswordIcon = view.FindViewById<TextView>(Resource.Id.SendCellHasPasswordIcon);
MaxAccessCountReachedIcon = view.FindViewById<TextView>(Resource.Id.SendCellMaxAccessCountReachedIcon);
ExpiredIcon = view.FindViewById<TextView>(Resource.Id.SendCellExpiredIcon);
PendingDeleteIcon = view.FindViewById<TextView>(Resource.Id.SendCellPendingDeleteIcon);
MoreButton = view.FindViewById<Button>(Resource.Id.SendCellButton);
MoreButton.Click += MoreButton_Click;
Icon.Typeface = _faTypeface;
DisabledIcon.Typeface = _faTypeface;
HasPasswordIcon.Typeface = _faTypeface;
MaxAccessCountReachedIcon.Typeface = _faTypeface;
ExpiredIcon.Typeface = _faTypeface;
PendingDeleteIcon.Typeface = _faTypeface;
MoreButton.Typeface = _miTypeface;
var small = (float)Device.GetNamedSize(NamedSize.Small, typeof(Label));
Icon.SetTextSize(ComplexUnitType.Pt, 10);
Name.SetTextSize(ComplexUnitType.Sp, (float)Device.GetNamedSize(NamedSize.Medium, typeof(Label)));
SubTitle.SetTextSize(ComplexUnitType.Sp, small);
DisabledIcon.SetTextSize(ComplexUnitType.Sp, small);
HasPasswordIcon.SetTextSize(ComplexUnitType.Sp, small);
MaxAccessCountReachedIcon.SetTextSize(ComplexUnitType.Sp, small);
ExpiredIcon.SetTextSize(ComplexUnitType.Sp, small);
PendingDeleteIcon.SetTextSize(ComplexUnitType.Sp, small);
MoreButton.SetTextSize(ComplexUnitType.Sp, 25);
if (!SendViewCell.ShowOptions)
{
MoreButton.Visibility = ViewStates.Gone;
}
AddView(view);
}
public SendViewCell SendViewCell { get; set; }
public Element Element => SendViewCell;
public TextView Icon { get; set; }
public TextView Name { get; set; }
public TextView SubTitle { get; set; }
public TextView DisabledIcon { get; set; }
public TextView HasPasswordIcon { get; set; }
public TextView MaxAccessCountReachedIcon { get; set; }
public TextView ExpiredIcon { get; set; }
public TextView PendingDeleteIcon { get; set; }
public Button MoreButton { get; set; }
public void UpdateCell(SendViewCell sendCell)
{
UpdateIconImage(sendCell);
var send = sendCell.Send;
Name.Text = send.Name;
SubTitle.Text = send.DisplayDate;
DisabledIcon.Visibility = send.Disabled ? ViewStates.Visible : ViewStates.Gone;
HasPasswordIcon.Visibility = send.HasPassword ? ViewStates.Visible : ViewStates.Gone;
MaxAccessCountReachedIcon.Visibility = send.MaxAccessCountReached ? ViewStates.Visible : ViewStates.Gone;
ExpiredIcon.Visibility = send.Expired ? ViewStates.Visible : ViewStates.Gone;
PendingDeleteIcon.Visibility = send.PendingDelete ? ViewStates.Visible : ViewStates.Gone;
}
public void UpdateIconImage(SendViewCell sendCell)
{
if (_currentTask != null && !_currentTask.IsCancelled && !_currentTask.IsCompleted)
{
_currentTask.Cancel();
}
var send = sendCell.Send;
var iconImage = sendCell.GetIconImage(send);
Icon.Text = iconImage;
}
public void UpdateColors(Color textColor, Color mutedColor,
Color iconDisabledColor)
{
Name.SetTextColor(textColor);
SubTitle.SetTextColor(mutedColor);
Icon.SetTextColor(mutedColor);
DisabledIcon.SetTextColor(mutedColor);
HasPasswordIcon.SetTextColor(mutedColor);
MaxAccessCountReachedIcon.SetTextColor(mutedColor);
ExpiredIcon.SetTextColor(mutedColor);
PendingDeleteIcon.SetTextColor(mutedColor);
MoreButton.SetTextColor(iconDisabledColor);
}
private void MoreButton_Click(object sender, EventArgs e)
{
if (SendViewCell.ButtonCommand?.CanExecute(SendViewCell.Send) ?? false)
{
SendViewCell.ButtonCommand.Execute(SendViewCell.Send);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
MoreButton.Click -= MoreButton_Click;
}
base.Dispose(disposing);
}
}
}

View File

@@ -0,0 +1,7 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/itemPressed">
<item
android:id="@android:id/mask"
android:drawable="@android:color/white" />
</ripple>

View File

@@ -0,0 +1,7 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/dark_primary">
<item
android:id="@android:id/mask"
android:drawable="@android:color/white" />
</ripple>

View File

@@ -0,0 +1,7 @@
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/nord_primary">
<item
android:id="@android:id/mask"
android:drawable="@android:color/white" />
</ripple>

View File

@@ -1,86 +0,0 @@
<?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"
android:minHeight="44dp"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="2.2dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="39.8dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center">
<bit.droid.renderers.IconImageView
android:id="@+id/CipherCellIconImage"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_gravity="center"
android:gravity="center" />
<TextView
android:id="@+id/CipherCellIcon"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:gravity="center"
android:text="[X]" />
</LinearLayout>
<LinearLayout
android:id="@+id/CipherCellContent"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:gravity="center"
android:paddingVertical="7.65dp">
<LinearLayout
android:id="@+id/CipherCellContentTop"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/CipherCellName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:text="Name" />
<TextView
android:id="@+id/CipherCellSharedIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf1e0;" />
<TextView
android:id="@+id/CipherCellAttachmentsIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf0c6;" />
</LinearLayout>
<TextView
android:id="@+id/CipherCellSubTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:text="SubTitle" />
</LinearLayout>
<Button
android:id="@+id/CipherCellButton"
android:layout_width="37dp"
android:layout_height="match_parent"
android:text="&#xe5d4;"
android:gravity="center"
android:padding="0dp"
android:background="@android:color/transparent" />
</LinearLayout>
</RelativeLayout>

View File

@@ -1,104 +0,0 @@
<?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"
android:minHeight="44dp"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="2.2dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="39.8dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center">
<TextView
android:id="@+id/SendCellIcon"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:gravity="center"
android:text="[X]" />
</LinearLayout>
<LinearLayout
android:id="@+id/SendCellContent"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:gravity="center"
android:paddingVertical="7.65dp">
<LinearLayout
android:id="@+id/SendCellContentTop"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/SendCellName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:text="Name" />
<TextView
android:id="@+id/SendCellDisabledIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf071;" />
<TextView
android:id="@+id/SendCellHasPasswordIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf084;" />
<TextView
android:id="@+id/SendCellMaxAccessCountReachedIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf05e;" />
<TextView
android:id="@+id/SendCellExpiredIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf017;" />
<TextView
android:id="@+id/SendCellPendingDeleteIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:singleLine="true"
android:text="&#xf1f8;" />
</LinearLayout>
<TextView
android:id="@+id/SendCellSubTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="end"
android:text="SubTitle" />
</LinearLayout>
<Button
android:id="@+id/SendCellButton"
android:layout_width="37dp"
android:layout_height="match_parent"
android:text="&#xe5d4;"
android:gravity="center"
android:padding="0dp"
android:background="@android:color/transparent" />
</LinearLayout>
</RelativeLayout>

View File

@@ -6,6 +6,7 @@
<color name="primary">#175DDC</color>
<color name="notificationBar">#1452BC</color>
<color name="border">#dddddd</color>
<color name="itemPressed">#bbbbbb</color>
<!-- Dark theme -->
<color name="dark_primary">#52bdfb</color>

View File

@@ -56,6 +56,12 @@
<compatibility-package
android:name="com.chrome.dev"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.cookiegames.smartcookie"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.cookiejarapps.android.smartcookieweb"
android:maxLongVersionCode="10000000000"/>
<compatibility-package
android:name="com.ecosia.android"
android:maxLongVersionCode="10000000000"/>

View File

@@ -1,7 +1,5 @@
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Javax.Crypto;
using Javax.Crypto.Spec;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
@@ -35,25 +33,5 @@ namespace Bit.Droid.Services
generator.Init(password, salt, iterations);
return ((KeyParameter)generator.GenerateDerivedMacParameters(keySize)).GetKey();
}
public byte[] AesGcmEncrypt(byte[] data, byte[] iv, byte[] key)
{
var secKey = new SecretKeySpec(key, "AES");
var cipher = Cipher.GetInstance("AES/GCM/NoPadding");
var gcmSpec = new GCMParameterSpec(128, iv);
cipher.Init(CipherMode.EncryptMode, secKey, gcmSpec);
var result = cipher.DoFinal(data);
return result;
}
public byte[] AesGcmDecrypt(byte[] data, byte[] iv, byte[] key)
{
var secKey = new SecretKeySpec(key, "AES");
var cipher = Cipher.GetInstance("AES/GCM/NoPadding");
var gcmSpec = new GCMParameterSpec(128, iv);
cipher.Init(CipherMode.DecryptMode, secKey, gcmSpec);
var result = cipher.DoFinal(data);
return result;
}
}
}

View File

@@ -307,7 +307,7 @@ namespace Bit.Droid.Services
public Task<string> DisplayPromptAync(string title = null, string description = null,
string text = null, string okButtonText = null, string cancelButtonText = null,
bool numericKeyboard = false, bool autofocus = true)
bool numericKeyboard = false, bool autofocus = true, bool password = false)
{
var activity = (MainActivity)CrossCurrentActivity.Current.Activity;
if (activity == null)
@@ -333,6 +333,10 @@ namespace Bit.Droid.Services
input.KeyListener = DigitsKeyListener.GetInstance(false, false);
#pragma warning restore CS0618 // Type or member is obsolete
}
if (password)
{
input.InputType = InputTypes.TextVariationPassword | InputTypes.ClassText;
}
input.ImeOptions = input.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
(ImeAction)ImeFlags.NoExtractUi;

View File

@@ -3,7 +3,9 @@ using Android.Content.PM;
namespace Bit.Droid
{
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop)]
[Activity(
NoHistory = true,
LaunchMode = LaunchMode.SingleTop)]
[IntentFilter(new[] { Android.Content.Intent.ActionView },
Categories = new[] { Android.Content.Intent.CategoryDefault, Android.Content.Intent.CategoryBrowsable },
DataScheme = "bitwarden")]

View File

@@ -19,7 +19,7 @@ namespace Bit.App.Abstractions
Task SelectFileAsync();
Task<string> DisplayPromptAync(string title = null, string description = null, string text = null,
string okButtonText = null, string cancelButtonText = null, bool numericKeyboard = false,
bool autofocus = true);
bool autofocus = true, bool password = false);
void RateApp();
bool SupportsFaceBiometric();
Task<bool> SupportsFaceBiometricAsync();

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace Bit.App.Abstractions
{
public interface IPasswordRepromptService
{
string[] ProtectedFields { get; }
Task<bool> ShowPasswordPromptAsync();
}
}

View File

@@ -13,11 +13,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="3.2.1" />
<PackageReference Include="Plugin.Fingerprint" Version="2.1.2" />
<PackageReference Include="Xamarin.Essentials" Version="1.5.3.2" />
<PackageReference Include="Microsoft.AppCenter.Crashes" Version="4.3.0" />
<PackageReference Include="Plugin.Fingerprint" Version="2.1.4" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.0" />
<PackageReference Include="Xamarin.FFImageLoading.Forms" Version="2.4.11.982" />
<PackageReference Include="Xamarin.Forms" Version="4.5.0.725" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2083" />
<PackageReference Include="ZXing.Net.Mobile" Version="2.4.1" />
<PackageReference Include="ZXing.Net.Mobile.Forms" Version="2.4.1" />
</ItemGroup>
@@ -411,4 +411,4 @@
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

View File

@@ -178,6 +178,10 @@ namespace Bit.App
SyncIfNeeded();
}
}
if (Device.RuntimePlatform == Device.Android)
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
}
_messagingService.Send("startEventTimer");
}
@@ -216,7 +220,6 @@ namespace Bit.App
private async void ResumedAsync()
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
_messagingService.Send("cancelVaultTimeoutTimer");
_messagingService.Send("startEventTimer");
await ClearCacheIfNeededAsync();
Prime();
@@ -313,11 +316,7 @@ namespace Bit.App
vaultTimeout = await _storageService.GetAsync<int?>(Constants.VaultTimeoutKey);
}
vaultTimeout = vaultTimeout.GetValueOrDefault(-1);
if (vaultTimeout > 0)
{
_messagingService.Send("scheduleVaultTimeoutTimer", vaultTimeout.Value);
}
else if (vaultTimeout == 0)
if (vaultTimeout == 0)
{
var action = await _storageService.GetAsync<string>(Constants.VaultTimeoutActionKey);
if (action == "logOut")

View File

@@ -1,114 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.CipherViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.CipherViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:ff="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
x:DataType="controls:CipherViewCellViewModel">
<Grid
x:Name="_grid"
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
x:DataType="controls:CipherViewCellViewModel">
<Grid.Resources>
<u:IconGlyphConverter x:Key="iconGlyphConverter"/>
<u:IconImageConverter x:Key="iconImageConverter"/>
<u:InverseBoolConverter x:Key="inverseBool" />
</Grid.Resources>
<Grid.BindingContext>
<controls:CipherViewCellViewModel />
</Grid.BindingContext>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<controls:FaLabel
Grid.Column="0"
HorizontalOptions="Center"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform"
IsVisible="{Binding ShowIconImage, Converter={StaticResource inverseBool}}"
Text="{Binding Cipher, Converter={StaticResource iconGlyphConverter}}"
AutomationProperties.IsInAccessibleTree="False" />
<ff:CachedImage
Grid.Column="0"
BitmapOptimizations="True"
ErrorPlaceholder="login.png"
LoadingPlaceholder="login.png"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="22"
HeightRequest="22"
IsVisible="{Binding ShowIconImage}"
Source="{Binding Cipher, Converter={StaticResource iconImageConverter}}"
AutomationProperties.IsInAccessibleTree="False" />
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center" Padding="0, 7">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
Text="{Binding Cipher.Name}" />
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="3"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Cipher.SubTitle}" />
<controls:FaLabel
x:Name="_icon"
Grid.Column="1"
Grid.Row="0"
Grid.Column="0"
HorizontalOptions="Center"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform"
AutomationProperties.IsInAccessibleTree="False" />
<ff:CachedImage
x:Name="_image"
Grid.Row="0"
Grid.Column="0"
BitmapOptimizations="True"
ErrorPlaceholder="login.png"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="22"
HeightRequest="22"
IsVisible="False"
AutomationProperties.IsInAccessibleTree="False" />
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
Text="{Binding Cipher.Name, Mode=OneWay}" />
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="3"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Cipher.SubTitle, Mode=OneWay}" />
<controls:FaLabel
Grid.Column="1"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1e0;"
IsVisible="{Binding Cipher.Shared, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Shared}" />
<controls:FaLabel
Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf0c6;"
IsVisible="{Binding Cipher.HasAttachments, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Attachments}" />
</Grid>
<controls:MiButton
Grid.Row="0"
Grid.Column="2"
Text="&#xe5d3;"
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
Clicked="MoreButton_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="EndAndExpand"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1e0;"
IsVisible="{Binding Cipher.Shared, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
AutomationProperties.Name="{u:I18n Shared}" />
<controls:FaLabel
Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf0c6;"
IsVisible="{Binding Cipher.HasAttachments, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Attachments}" />
</Grid>
</ViewCell>
<controls:MiButton
Grid.Row="0"
Grid.Column="2"
Text="&#xe5d3;"
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
Clicked="MoreButton_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="EndAndExpand"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
</controls:ExtendedGrid>

View File

@@ -1,45 +1,26 @@
using Bit.App.Pages;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using System;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public partial class CipherViewCell : ViewCell
public partial class CipherViewCell : ExtendedGrid
{
public static readonly BindableProperty CipherProperty = BindableProperty.Create(
nameof(Cipher), typeof(CipherView), typeof(CipherViewCell), default(CipherView), BindingMode.OneWay);
public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
nameof(WebsiteIconsEnabled), typeof(bool), typeof(CipherViewCell), true, BindingMode.OneWay);
nameof(WebsiteIconsEnabled), typeof(bool?), typeof(CipherViewCell));
public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
nameof(ButtonCommand), typeof(Command<CipherView>), typeof(CipherViewCell));
private readonly IEnvironmentService _environmentService;
private CipherViewCellViewModel _viewModel;
private bool _usingNativeCell;
public CipherViewCell()
{
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
if (Device.RuntimePlatform == Device.iOS)
{
InitializeComponent();
_viewModel = _grid.BindingContext as CipherViewCellViewModel;
}
else
{
_usingNativeCell = true;
}
InitializeComponent();
}
public bool WebsiteIconsEnabled
public bool? WebsiteIconsEnabled
{
get => (bool)GetValue(WebsiteIconsEnabledProperty);
set => SetValue(WebsiteIconsEnabledProperty, value);
@@ -60,130 +41,31 @@ namespace Bit.App.Controls
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (_usingNativeCell)
{
return;
}
if (propertyName == CipherProperty.PropertyName)
{
_viewModel.Cipher = Cipher;
if (Cipher == null)
{
return;
}
BindingContext = new CipherViewCellViewModel(Cipher, WebsiteIconsEnabled ?? false);
}
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (_usingNativeCell)
else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
{
return;
if (Cipher == null)
{
return;
}
((CipherViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
}
_image.Source = null;
CipherView cipher = null;
if (BindingContext is GroupingsPageListItem groupingsPageListItem)
{
cipher = groupingsPageListItem.Cipher;
}
else if (BindingContext is CipherView cv)
{
cipher = cv;
}
if (cipher != null)
{
var iconImage = GetIconImage(cipher);
if (iconImage.Item2 != null)
{
_image.IsVisible = true;
_icon.IsVisible = false;
_image.Source = iconImage.Item2;
_image.LoadingPlaceholder = "login.png";
}
else
{
_image.IsVisible = false;
_icon.IsVisible = true;
_icon.Text = iconImage.Item1;
}
}
}
public Tuple<string, string> GetIconImage(CipherView cipher)
{
string icon = null;
string image = null;
switch (cipher.Type)
{
case CipherType.Login:
var loginIconImage = GetLoginIconImage(cipher);
icon = loginIconImage.Item1;
image = loginIconImage.Item2;
break;
case CipherType.SecureNote:
icon = "";
break;
case CipherType.Card:
icon = "";
break;
case CipherType.Identity:
icon = "";
break;
default:
break;
}
return new Tuple<string, string>(icon, image);
}
private Tuple<string, string> GetLoginIconImage(CipherView cipher)
{
string icon = "";
string image = null;
if (cipher.Login.Uri != null)
{
var hostnameUri = cipher.Login.Uri;
var isWebsite = false;
if (hostnameUri.StartsWith(Constants.AndroidAppProtocol))
{
icon = "";
}
else if (hostnameUri.StartsWith(Constants.iOSAppProtocol))
{
icon = "";
}
else if (WebsiteIconsEnabled && !hostnameUri.Contains("://") && hostnameUri.Contains("."))
{
hostnameUri = string.Concat("http://", hostnameUri);
isWebsite = true;
}
else if (WebsiteIconsEnabled)
{
isWebsite = hostnameUri.StartsWith("http") && hostnameUri.Contains(".");
}
if (WebsiteIconsEnabled && isWebsite)
{
var hostname = CoreHelpers.GetHostname(hostnameUri);
var iconsUrl = _environmentService.IconsUrl;
if (string.IsNullOrWhiteSpace(iconsUrl))
{
if (!string.IsNullOrWhiteSpace(_environmentService.BaseUrl))
{
iconsUrl = string.Format("{0}/icons", _environmentService.BaseUrl);
}
else
{
iconsUrl = "https://icons.bitwarden.net";
}
}
image = string.Format("{0}/{1}/icon.png", iconsUrl, hostname);
}
}
return new Tuple<string, string>(icon, image);
}
private void MoreButton_Clicked(object sender, EventArgs e)
{
ButtonCommand?.Execute(Cipher);
var cipher = ((sender as MiButton)?.BindingContext as CipherViewCellViewModel)?.Cipher;
if (cipher != null)
{
ButtonCommand?.Execute(cipher);
}
}
}
}

View File

@@ -6,11 +6,30 @@ namespace Bit.App.Controls
public class CipherViewCellViewModel : ExtendedViewModel
{
private CipherView _cipher;
private bool _websiteIconsEnabled;
public CipherViewCellViewModel(CipherView cipherView, bool websiteIconsEnabled)
{
Cipher = cipherView;
WebsiteIconsEnabled = websiteIconsEnabled;
}
public CipherView Cipher
{
get => _cipher;
set => SetProperty(ref _cipher, value);
}
public bool WebsiteIconsEnabled
{
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
public bool ShowIconImage
{
get => WebsiteIconsEnabled && !string.IsNullOrWhiteSpace(Cipher.Login?.Uri) &&
Cipher.Login.Uri.StartsWith("http");
}
}
}

View File

@@ -0,0 +1,8 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedCollectionView : CollectionView
{
}
}

View File

@@ -0,0 +1,8 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedGrid : Grid
{
}
}

View File

@@ -1,12 +0,0 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedListView : ListView
{
public ExtendedListView() { }
public ExtendedListView(ListViewCachingStrategy cachingStrategy)
: base(cachingStrategy) { }
}
}

View File

@@ -0,0 +1,8 @@
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedStackLayout : StackLayout
{
}
}

View File

@@ -1,137 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.SendViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities">
<controls:ExtendedGrid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Controls.SendViewCell"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
x:DataType="controls:SendViewCellViewModel">
<Grid
x:Name="_grid"
StyleClass="list-row, list-row-platform"
RowSpacing="0"
ColumnSpacing="0"
x:DataType="controls:SendViewCellViewModel">
<Grid.Resources>
<u:SendIconGlyphConverter x:Key="sendIconGlyphConverter"/>
</Grid.Resources>
<Grid.BindingContext>
<controls:SendViewCellViewModel />
</Grid.BindingContext>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<controls:FaLabel
Grid.Row="0"
Grid.Column="0"
HorizontalOptions="Center"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform"
Text="{Binding Send, Converter={StaticResource sendIconGlyphConverter}}"
AutomationProperties.IsInAccessibleTree="False" />
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center" Padding="0, 7">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="60" />
</Grid.ColumnDefinitions>
<controls:FaLabel
x:Name="_icon"
Grid.Row="0"
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
HorizontalOptions="Center"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform"
AutomationProperties.IsInAccessibleTree="False" />
<Grid RowSpacing="0" ColumnSpacing="0" Grid.Row="0" Grid.Column="1" VerticalOptions="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
Text="{Binding Send.Name, Mode=OneWay}" />
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="6"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Send.DisplayDate, Mode=OneWay}" />
<controls:FaLabel
Grid.Column="1"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf071;"
IsVisible="{Binding Send.Disabled, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Disabled}" />
<controls:FaLabel
Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf084;"
IsVisible="{Binding Send.HasPassword, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Password}" />
<controls:FaLabel
Grid.Column="3"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf05e;"
IsVisible="{Binding Send.MaxAccessCountReached, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n MaxAccessCountReached}" />
<controls:FaLabel
Grid.Column="4"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf017;"
IsVisible="{Binding Send.Expired, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Expired}" />
<controls:FaLabel
Grid.Column="5"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1f8;"
IsVisible="{Binding Send.PendingDelete, Mode=OneWay}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n PendingDelete}" />
</Grid>
<controls:MiButton
Grid.Row="0"
Grid.Column="2"
Text="&#xe5d3;"
IsVisible="{Binding ShowOptions, Mode=OneWay}"
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
Clicked="MoreButton_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="EndAndExpand"
StyleClass="list-title, list-title-platform"
Text="{Binding Send.Name}" />
<Label
LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="6"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Send.DisplayDate}" />
<controls:FaLabel
Grid.Column="1"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf071;"
IsVisible="{Binding Send.Disabled, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
AutomationProperties.Name="{u:I18n Disabled}" />
<controls:FaLabel
Grid.Column="2"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf084;"
IsVisible="{Binding Send.HasPassword, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Password}" />
<controls:FaLabel
Grid.Column="3"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf05e;"
IsVisible="{Binding Send.MaxAccessCountReached, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n MaxAccessCountReached}" />
<controls:FaLabel
Grid.Column="4"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf017;"
IsVisible="{Binding Send.Expired, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Expired}" />
<controls:FaLabel
Grid.Column="5"
Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-title-icon"
Margin="5, 0, 0, 0"
Text="&#xf1f8;"
IsVisible="{Binding Send.PendingDelete, Mode=OneTime}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n PendingDelete}" />
</Grid>
</ViewCell>
<controls:MiButton
Grid.Row="0"
Grid.Column="2"
Text="&#xe5d3;"
IsVisible="{Binding ShowOptions, Mode=OneWay}"
StyleClass="list-row-button, list-row-button-platform, btn-disabled"
Clicked="MoreButton_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="EndAndExpand"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
</controls:ExtendedGrid>

View File

@@ -1,14 +1,10 @@
using System;
using Bit.App.Pages;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public partial class SendViewCell : ViewCell
public partial class SendViewCell : ExtendedGrid
{
public static readonly BindableProperty SendProperty = BindableProperty.Create(
nameof(Send), typeof(SendView), typeof(SendViewCell), default(SendView), BindingMode.OneWay);
@@ -17,25 +13,11 @@ namespace Bit.App.Controls
nameof(ButtonCommand), typeof(Command<SendView>), typeof(SendViewCell));
public static readonly BindableProperty ShowOptionsProperty = BindableProperty.Create(
nameof(ShowOptions), typeof(bool), typeof(SendViewCell));
private readonly IEnvironmentService _environmentService;
private SendViewCellViewModel _viewModel;
private bool _usingNativeCell;
nameof(ShowOptions), typeof(bool), typeof(SendViewCell), true, BindingMode.OneWay);
public SendViewCell()
{
_environmentService = ServiceContainer.Resolve<IEnvironmentService>("environmentService");
if (Device.RuntimePlatform == Device.iOS)
{
InitializeComponent();
_viewModel = _grid.BindingContext as SendViewCellViewModel;
}
else
{
_usingNativeCell = true;
}
InitializeComponent();
}
public SendView Send
@@ -52,72 +34,30 @@ namespace Bit.App.Controls
public bool ShowOptions
{
get => GetValue(ShowOptionsProperty) is bool && (bool)GetValue(ShowOptionsProperty);
get => (bool)GetValue(ShowOptionsProperty);
set => SetValue(ShowOptionsProperty, value);
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (_usingNativeCell)
{
return;
}
if (propertyName == SendProperty.PropertyName)
{
_viewModel.Send = Send;
if (Send == null)
{
return;
}
BindingContext = new SendViewCellViewModel(Send, ShowOptions);
}
else if (propertyName == ShowOptionsProperty.PropertyName)
{
_viewModel.ShowOptions = ShowOptions;
}
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (_usingNativeCell)
{
return;
}
SendView send = null;
if (BindingContext is SendGroupingsPageListItem sendGroupingsPageListItem)
{
send = sendGroupingsPageListItem.Send;
}
else if (BindingContext is SendView sv)
{
send = sv;
}
if (send != null)
{
var iconImage = GetIconImage(send);
_icon.IsVisible = true;
_icon.Text = iconImage;
}
}
public string GetIconImage(SendView send)
{
string icon = null;
switch (send.Type)
{
case SendType.Text:
icon = "\uf0f6"; // fa-file-text-o
break;
case SendType.File:
icon = "\uf016"; // fa-file-o
break;
default:
break;
}
return icon;
}
private void MoreButton_Clicked(object sender, EventArgs e)
{
ButtonCommand?.Execute(Send);
var send = ((sender as MiButton)?.BindingContext as SendViewCellViewModel)?.Send;
if (send != null)
{
ButtonCommand?.Execute(send);
}
}
}
}

View File

@@ -8,6 +8,12 @@ namespace Bit.App.Controls
private SendView _send;
private bool _showOptions;
public SendViewCellViewModel(SendView sendView, bool showOptions)
{
Send = sendView;
ShowOptions = showOptions;
}
public SendView Send
{
get => _send;

View File

@@ -8,6 +8,7 @@ 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 Xamarin.Forms;
@@ -37,7 +38,6 @@ namespace Bit.App.Pages
private string _biometricButtonText;
private string _loggedInAsText;
private string _lockedVerifyText;
private int _invalidPinAttempts = 0;
private Tuple<bool, bool> _pinSet;
public LockPageViewModel()
@@ -208,6 +208,7 @@ namespace Bit.App.Pages
if (!failed)
{
Pin = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(key);
}
}
@@ -217,6 +218,7 @@ namespace Bit.App.Pages
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
failed = false;
Pin = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(key);
}
}
@@ -226,8 +228,8 @@ namespace Bit.App.Pages
}
if (failed)
{
_invalidPinAttempts++;
if (_invalidPinAttempts >= 5)
var invalidUnlockAttempts = await AppHelpers.IncrementInvalidUnlockAttemptsAsync();
if (invalidUnlockAttempts >= 5)
{
_messagingService.Send("logout");
return;
@@ -239,32 +241,31 @@ namespace Bit.App.Pages
else
{
var key = await _cryptoService.MakeKeyAsync(MasterPassword, _email, kdf, kdfIterations);
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key);
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
var passwordValid = false;
if (keyHash != null)
if (storedKeyHash != null)
{
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
if (storedKeyHash != null)
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key);
}
else
{
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
var request = new PasswordVerificationRequest();
request.MasterPasswordHash = keyHash;
try
{
passwordValid = storedKeyHash == keyHash;
await _apiService.PostAccountVerifyPasswordAsync(request);
passwordValid = true;
var localKeyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization);
await _cryptoService.SetKeyHashAsync(localKeyHash);
}
else
catch (Exception e)
{
await _deviceActionService.ShowLoadingAsync(AppResources.Loading);
var request = new PasswordVerificationRequest();
request.MasterPasswordHash = keyHash;
try
{
await _apiService.PostAccountVerifyPasswordAsync(request);
passwordValid = true;
await _cryptoService.SetKeyHashAsync(keyHash);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", e.GetType(), e.StackTrace);
}
await _deviceActionService.HideLoadingAsync();
System.Diagnostics.Debug.WriteLine(">>> {0}: {1}", e.GetType(), e.StackTrace);
}
await _deviceActionService.HideLoadingAsync();
}
if (passwordValid)
{
@@ -278,6 +279,7 @@ namespace Bit.App.Pages
_vaultTimeoutService.PinProtectedKey = await _cryptoService.EncryptAsync(key.Key, pinKey);
}
MasterPassword = string.Empty;
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await SetKeyAndContinueAsync(key);
// Re-enable biometrics
@@ -288,6 +290,12 @@ namespace Bit.App.Pages
}
else
{
var invalidUnlockAttempts = await AppHelpers.IncrementInvalidUnlockAttemptsAsync();
if (invalidUnlockAttempts >= 5)
{
_messagingService.Send("logout");
return;
}
await _platformUtilsService.ShowDialogAsync(AppResources.InvalidMasterPassword,
AppResources.AnErrorHasOccurred);
}

View File

@@ -6,6 +6,7 @@ using Bit.Core.Exceptions;
using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using Bit.App.Utilities;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -125,6 +126,7 @@ namespace Bit.App.Pages
{
await _storageService.RemoveAsync(Keys_RememberedEmail);
}
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
await _deviceActionService.HideLoadingAsync();
if (response.TwoFactor)
{

View File

@@ -14,7 +14,6 @@
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
<ToolbarItem Text="{u:I18n LogIn}" Clicked="LogIn_Clicked" />
</ContentPage.ToolbarItems>
<ScrollView>
@@ -36,6 +35,10 @@
ReturnCommand="{Binding LogInCommand}" />
</StackLayout>
</StackLayout>
<StackLayout Padding="10, 0">
<Button Text="{u:I18n LogIn}"
Clicked="LogIn_Clicked"></Button>
</StackLayout>
</StackLayout>
</ScrollView>

View File

@@ -5,6 +5,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using Bit.App.Utilities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Domain;
@@ -182,6 +183,7 @@ namespace Bit.App.Pages
try
{
var response = await _authService.LogInSsoAsync(code, codeVerifier, redirectUri);
await AppHelpers.ResetInvalidUnlockAttemptsAsync();
if (RememberOrgIdentifier)
{
await _storageService.SaveAsync(Keys_RememberedOrgIdentifier, OrgIdentifier);

View File

@@ -138,7 +138,8 @@ namespace Bit.App.Pages
var kdfIterations = 100000;
var email = await _userService.GetEmailAsync();
var key = await _cryptoService.MakeKeyAsync(MasterPassword, email, kdf, kdfIterations);
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key);
var masterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
var localMasterPasswordHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.LocalAuthorization);
Tuple<SymmetricCryptoKey, EncString> encKey;
var existingEncKey = await _cryptoService.GetEncKeyAsync();
@@ -174,7 +175,7 @@ namespace Bit.App.Pages
await _userService.SetInformationAsync(await _userService.GetUserIdAsync(),
await _userService.GetEmailAsync(), kdf, kdfIterations);
await _cryptoService.SetKeyAsync(key);
await _cryptoService.SetKeyHashAsync(masterPasswordHash);
await _cryptoService.SetKeyHashAsync(localMasterPasswordHash);
await _cryptoService.SetEncKeyAsync(encKey.Item2.EncryptedString);
await _cryptoService.SetEncPrivateKeyAsync(keys.Item2.EncryptedString);
await _deviceActionService.HideLoadingAsync();

View File

@@ -16,14 +16,21 @@
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_cancelItem" />
<ToolbarItem Text="{u:I18n Continue}" Clicked="Continue_Clicked" Order="Primary"
x:Name="_continueItem" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:IsNullConverter x:Key="isNull" />
<ToolbarItem Icon="more_vert.png" Clicked="More_Clicked" Order="Primary"
x:Name="_moreItem" x:Key="moreItem"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
<ToolbarItem Text="{u:I18n UseAnotherTwoStepMethod}"
Clicked="Methods_Clicked"
Order="Secondary"
x:Name="_useAnotherTwoStepMethod"
x:Key="useAnotherTwoStepMethod" />
</ResourceDictionary>
</ContentPage.Resources>
@@ -45,7 +52,8 @@
Keyboard="Numeric"
StyleClass="box-value"
ReturnType="Go"
ReturnCommand="{Binding SubmitCommand}" />
ReturnCommand="{Binding SubmitCommand}"
TextChanged="Token_TextChanged"/>
</StackLayout>
<StackLayout StyleClass="box-row, box-row-switch">
<Label
@@ -123,6 +131,12 @@
Margin="10, 20, 10, 10"
HorizontalTextAlignment="Center" />
</StackLayout>
<Button Text="{u:I18n Continue}"
IsEnabled="{Binding EnableContinue}"
IsVisible="{Binding ShowContinue}"
Clicked="Continue_Clicked"
Margin="10, 0"
x:Name="_continue"></Button>
<Button Text="{u:I18n SendVerificationCodeAgain}"
IsVisible="{Binding EmailMethod}"
Clicked="ResendEmail_Clicked"
@@ -131,9 +145,6 @@
IsVisible="{Binding ShowTryAgain}"
Clicked="TryAgain_Clicked"
Margin="10, 0"></Button>
<Button Text="{u:I18n UseAnotherTwoStepMethod}"
Clicked="Methods_Clicked"
Margin="10, 0"></Button>
</StackLayout>
</ScrollView>

View File

@@ -1,5 +1,6 @@
using Bit.App.Controls;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System;
@@ -45,26 +46,17 @@ namespace Bit.App.Pages
{
ToolbarItems.Remove(_cancelItem);
}
if (Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(_moreItem);
} else
{
ToolbarItems.Add(_useAnotherTwoStepMethod);
}
}
public HybridWebView DuoWebView { get; set; }
public void AddContinueButton()
{
if (!ToolbarItems.Contains(_continueItem))
{
ToolbarItems.Add(_continueItem);
}
}
public void RemoveContinueButton()
{
if (ToolbarItems.Contains(_continueItem))
{
ToolbarItems.Remove(_continueItem);
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
@@ -145,6 +137,21 @@ namespace Bit.App.Pages
}
}
private async void More_Clicked(object sender, EventArgs e)
{
if (!DoOnce())
{
return;
}
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel, null, AppResources.UseAnotherTwoStepMethod);
if (selection == AppResources.UseAnotherTwoStepMethod)
{
await _vm.AnotherMethodAsync();
}
}
private async void ResendEmail_Clicked(object sender, EventArgs e)
{
if (DoOnce())
@@ -195,5 +202,10 @@ namespace Bit.App.Pages
Application.Current.MainPage = new TabsPage(_appOptions, previousPage);
}
}
private void Token_TextChanged(object sender, TextChangedEventArgs e)
{
_vm.EnableContinue = !string.IsNullOrWhiteSpace(e.NewTextValue);
}
}
}

View File

@@ -32,6 +32,8 @@ namespace Bit.App.Pages
private string _totpInstruction;
private string _webVaultUrl = "https://vault.bitwarden.com";
private bool _authingWithSso = false;
private bool _enableContinue = false;
private bool _showContinue = true;
public TwoFactorPageViewModel()
{
@@ -73,6 +75,18 @@ namespace Bit.App.Pages
public bool ShowTryAgain => YubikeyMethod && Device.RuntimePlatform == Device.iOS;
public bool ShowContinue
{
get => _showContinue;
set => SetProperty(ref _showContinue, value);
}
public bool EnableContinue
{
get => _enableContinue;
set => SetProperty(ref _enableContinue, value);
}
public string YubikeyInstruction => Device.RuntimePlatform == Device.iOS ? AppResources.YubiKeyInstructionIos :
AppResources.YubiKeyInstruction;
@@ -169,14 +183,7 @@ namespace Bit.App.Pages
{
_messagingService.Send("listenYubiKeyOTP", false);
}
if (SelectedProviderType == null || DuoMethod)
{
page.RemoveContinueButton();
}
else
{
page.AddContinueButton();
}
ShowContinue = !(SelectedProviderType == null || DuoMethod);
}
public async Task SubmitAsync()
@@ -245,7 +252,7 @@ namespace Bit.App.Pages
{
_platformUtilsService.LaunchUri("https://help.bitwarden.com/article/lost-two-step-device/");
}
else if (method != AppResources.Cancel)
else if (method != AppResources.Cancel && method != null)
{
var selected = supportedProviders.FirstOrDefault(p => p.Name == method)?.Type;
if (selected == SelectedProviderType)

View File

@@ -43,57 +43,53 @@
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"></Label>
<ListView x:Name="_listView"
<controls:ExtendedCollectionView
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
ItemsSource="{Binding History}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
StyleClass="list, list-platform">
<ListView.ItemTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="domain:GeneratedPasswordHistory">
<ViewCell>
<Grid
StyleClass="list-row, list-row-platform"
Padding="10"
RowSpacing="0"
ColumnSpacing="10">
<Grid
StyleClass="list-row, list-row-platform"
Padding="10"
RowSpacing="0"
ColumnSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:MonoLabel LineBreakMode="CharacterWrap"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
TextType="Html"
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
<Label LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
<controls:FaButton
StyleClass="list-row-button, list-row-button-platform"
Text="&#xf24d;"
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CopyPassword}" />
</Grid>
</ViewCell>
<controls:MonoLabel LineBreakMode="CharacterWrap"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
TextType="Html"
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
<Label LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
<controls:FaButton
StyleClass="list-row-button, list-row-button-platform"
Text="&#xf0ea;"
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CopyPassword}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</CollectionView.ItemTemplate>
</controls:ExtendedCollectionView>
</StackLayout>
</pages:BaseContentPage>

View File

@@ -294,24 +294,23 @@
x:Name="_btnOptions"
StyleClass="box-row-button"
TextColor="{StaticResource PrimaryColor}"
Margin="0"
Clicked="ToggleOptions_Clicked" />
Margin="0" />
<controls:FaButton
x:Name="_btnOptionsUp"
Text="&#xf077;"
StyleClass="box-row-button"
TextColor="{StaticResource PrimaryColor}"
Clicked="ToggleOptions_Clicked"
IsVisible="{Binding ShowOptions}" />
IsVisible="False" />
<controls:FaButton
x:Name="_btnOptionsDown"
Text="&#xf078;"
StyleClass="box-row-button"
TextColor="{StaticResource PrimaryColor}"
Clicked="ToggleOptions_Clicked"
IsVisible="{Binding ShowOptions, Converter={StaticResource inverseBool}}" />
IsVisible="False" />
</StackLayout>
<StackLayout IsVisible="{Binding ShowOptions}">
<StackLayout IsVisible="True">
<StackLayout
StyleClass="box-row"
Margin="0,10,0,0">

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
@@ -16,6 +17,7 @@ namespace Bit.App.Pages
public partial class SendAddEditPage : BaseContentPage
{
private readonly IBroadcasterService _broadcasterService;
private readonly IVaultTimeoutService _vaultTimeoutService;
private AppOptions _appOptions;
private SendAddEditPageViewModel _vm;
@@ -26,6 +28,7 @@ namespace Bit.App.Pages
SendType? type = null)
{
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
_appOptions = appOptions;
InitializeComponent();
_vm = BindingContext as SendAddEditPageViewModel;
@@ -79,6 +82,14 @@ namespace Bit.App.Pages
protected override async void OnAppearing()
{
base.OnAppearing();
if (!await AppHelpers.IsVaultTimeoutImmediateAsync())
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
}
if (await _vaultTimeoutService.IsLockedAsync())
{
return;
}
await _vm.InitAsync();
_broadcasterService.Subscribe(nameof(SendAddEditPage), message =>
{
@@ -109,6 +120,15 @@ namespace Bit.App.Pages
});
}
protected override bool OnBackButtonPressed()
{
if (_vm.IsAddFromShare && Device.RuntimePlatform == Device.Android)
{
_appOptions.CreateSend = null;
}
return base.OnBackButtonPressed();
}
protected override void OnDisappearing()
{
base.OnDisappearing();

View File

@@ -45,7 +45,6 @@ namespace Bit.App.Pages
};
private bool _disableHideEmail;
private bool _sendOptionsPolicyInEffect;
private bool _disableHideEmailControl;
public SendAddEditPageViewModel()
{

View File

@@ -44,34 +44,32 @@
<controls:SendViewCell
Send="{Binding Send}"
ButtonCommand="{Binding BindingContext.SendOptionsCommand, Source={x:Reference _page}}"
ShowOptions="{Binding ShowOptions}" />
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}" />
</DataTemplate>
<DataTemplate x:Key="sendGroupTemplate"
x:DataType="pages:SendGroupingsPageListItem">
<ViewCell>
<StackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform">
<controls:FaLabel.Effects>
<effects:FixedSizeEffect />
</controls:FaLabel.Effects>
</controls:FaLabel>
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title" />
<Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub" />
</StackLayout>
</ViewCell>
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform">
<controls:FaLabel.Effects>
<effects:FixedSizeEffect />
</controls:FaLabel.Effects>
</controls:FaLabel>
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title" />
<Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub" />
</controls:ExtendedStackLayout>
</DataTemplate>
<pages:SendGroupingsPageListItemSelector x:Key="sendListItemDataTemplateSelector"
@@ -103,32 +101,25 @@
Text="{Binding NoDataText}"
HorizontalTextAlignment="Center" />
<Button
Text="{u:I18n AddAnItem}"
Clicked="AddButton_Clicked"
IsVisible="{Binding ShowAddSendButton}" />
Text="{u:I18n AddASend}"
Clicked="AddButton_Clicked" />
</StackLayout>
<controls:ExtendedListView
x:Name="_listView"
<RefreshView
IsVisible="{Binding ShowList}"
ItemsSource="{Binding GroupedSends}"
VerticalOptions="FillAndExpand"
HasUnevenRows="True"
RowHeight="-1"
RefreshCommand="{Binding RefreshCommand}"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding Refreshing}"
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
IsGroupingEnabled="True"
ItemSelected="RowSelected"
StyleClass="list, list-platform">
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
Command="{Binding RefreshCommand}">
<controls:ExtendedCollectionView
ItemsSource="{Binding GroupedSends}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<ListView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:SendGroupingsPageListGroup">
<ViewCell>
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:SendGroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
@@ -146,10 +137,10 @@
<BoxView
StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</controls:ExtendedListView>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</RefreshView>
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -20,14 +20,13 @@ namespace Bit.App.Pages
private readonly string _pageName;
private AppOptions _appOptions;
private PreviousPageInfo _previousPage;
public SendGroupingsPage(bool mainPage, SendType? type = null, string pageTitle = null,
AppOptions appOptions = null, PreviousPageInfo previousPage = null)
AppOptions appOptions = null)
{
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
_pageName = string.Concat(nameof(SendGroupingsPage), "_", DateTime.UtcNow.Ticks);
InitializeComponent();
ListView = _listView;
SetActivityIndicator(_mainContent);
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
@@ -37,7 +36,6 @@ namespace Bit.App.Pages
_vm.MainPage = mainPage;
_vm.Type = type;
_appOptions = appOptions;
_previousPage = previousPage;
if (pageTitle != null)
{
_vm.PageTitle = pageTitle;
@@ -46,7 +44,10 @@ namespace Bit.App.Pages
if (Device.RuntimePlatform == Device.iOS)
{
_absLayout.Children.Remove(_fab);
ToolbarItems.Add(_aboutIconItem);
if (type == null)
{
ToolbarItems.Add(_aboutIconItem);
}
ToolbarItems.Add(_addItem);
}
else
@@ -57,8 +58,6 @@ namespace Bit.App.Pages
}
}
public ExtendedListView ListView { get; set; }
protected override async void OnAppearing()
{
base.OnAppearing();
@@ -136,14 +135,14 @@ namespace Bit.App.Pages
}
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (!(e.SelectedItem is SendGroupingsPageListItem item))
if (!(e.CurrentSelection?.FirstOrDefault() is SendGroupingsPageListItem item))
{
return;
}

View File

@@ -7,10 +7,10 @@ namespace Bit.App.Pages
public SendGroupingsPageListGroup(string name, int count, bool doUpper = true, bool first = false)
: this(new List<SendGroupingsPageListItem>(), name, count, doUpper, first) { }
public SendGroupingsPageListGroup(List<SendGroupingsPageListItem> groupItems, string name, int count,
public SendGroupingsPageListGroup(List<SendGroupingsPageListItem> sendGroupItems, string name, int count,
bool doUpper = true, bool first = false)
{
AddRange(groupItems);
AddRange(sendGroupItems);
if (string.IsNullOrWhiteSpace(name))
{
Name = "-";

View File

@@ -23,7 +23,6 @@ namespace Bit.App.Pages
private bool _doingLoad;
private bool _loading;
private bool _loaded;
private bool _showAddSendButton;
private bool _showNoData;
private bool _showList;
private bool _syncRefreshing;
@@ -91,11 +90,6 @@ namespace Bit.App.Pages
get => _loaded;
set => SetProperty(ref _loaded, value);
}
public bool ShowAddSendButton
{
get => _showAddSendButton;
set => SetProperty(ref _showAddSendButton, value);
}
public bool ShowNoData
{
get => _showNoData;

View File

@@ -60,23 +60,22 @@
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center" />
<ListView x:Name="_listView"
<controls:ExtendedCollectionView
IsVisible="{Binding ShowList}"
ItemsSource="{Binding Sends}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
ItemSelected="RowSelected"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<ListView.ItemTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="views:SendView">
<controls:SendViewCell
Send="{Binding .}"
ButtonCommand="{Binding BindingContext.SendOptionsCommand, Source={x:Reference _page}}"
ShowOptions="{Binding BindingContext.SendEnabled, Source={x:Reference _page}}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</CollectionView.ItemTemplate>
</controls:ExtendedCollectionView>
</StackLayout>
</pages:BaseContentPage>

View File

@@ -1,4 +1,6 @@
using System;
using System;
using System.Linq;
using Bit.App.Controls;
using Bit.App.Resources;
using Bit.Core.Models.View;
using Xamarin.Forms;
@@ -87,15 +89,15 @@ namespace Bit.App.Pages
Navigation.PopModalAsync(false);
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (e.SelectedItem is SendView send)
if (e.CurrentSelection?.FirstOrDefault() is SendView send)
{
await _vm.SelectSendAsync(send);
}

View File

@@ -103,11 +103,9 @@ namespace Bit.App.Pages
return;
}
var keyHash = await _cryptoService.HashPasswordAsync(_masterPassword, null);
var passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(_masterPassword, null);
MasterPassword = string.Empty;
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
if (storedKeyHash == null || keyHash == null || storedKeyHash != keyHash)
if (!passwordValid)
{
await _platformUtilsService.ShowDialogAsync(_i18nService.T("InvalidMasterPassword"));
return;
@@ -128,7 +126,7 @@ namespace Bit.App.Pages
fileFormat = fileFormat == "encrypted_json" ? "json" : fileFormat;
_defaultFilename = _exportService.GetFileName(null, fileFormat);
_exportResult = Encoding.ASCII.GetBytes(data);
_exportResult = Encoding.UTF8.GetBytes(data);
if (!_deviceActionService.SaveFile(_exportResult, null, _defaultFilename, null))
{

View File

@@ -32,27 +32,25 @@
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"></Label>
<ListView x:Name="_listView"
<controls:ExtendedCollectionView
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
ItemsSource="{Binding Folders}"
VerticalOptions="FillAndExpand"
CachingStrategy="RecycleElement"
ItemSelected="RowSelected"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<ListView.ItemTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="views:FolderView">
<ViewCell>
<StackLayout
StyleClass="list-row, list-row-platform"
Padding="10">
<Label LineBreakMode="TailTruncation"
StyleClass="list-title, list-title-platform"
Text="{Binding Name, Mode=OneWay}" />
</StackLayout>
</ViewCell>
<controls:ExtendedStackLayout
StyleClass="list-row, list-row-platform"
Padding="10">
<Label LineBreakMode="TailTruncation"
StyleClass="list-title, list-title-platform"
Text="{Binding Name, Mode=OneWay}" />
</controls:ExtendedStackLayout>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</CollectionView.ItemTemplate>
</controls:ExtendedCollectionView>
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -1,5 +1,7 @@
using Bit.Core.Models.View;
using System;
using System.Linq;
using Bit.App.Controls;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -32,14 +34,14 @@ namespace Bit.App.Pages
}, _mainContent);
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (!(e.SelectedItem is FolderView folder))
if (!(e.CurrentSelection?.FirstOrDefault() is FolderView folder))
{
return;
}

View File

@@ -19,23 +19,21 @@
<DataTemplate
x:Key="regularTemplate"
x:DataType="pages:SettingsPageListItem">
<ViewCell>
<StackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="StartAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<Label Text="{Binding SubLabel, Mode=OneWay}"
IsVisible="{Binding SubLabel, Converter={StaticResource stringHasValue}}"
HorizontalOptions="End"
HorizontalTextAlignment="End"
VerticalOptions="CenterAndExpand"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub" />
</StackLayout>
</ViewCell>
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="StartAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<Label Text="{Binding SubLabel, Mode=OneWay}"
IsVisible="{Binding SubLabel, Converter={StaticResource stringHasValue}}"
HorizontalOptions="End"
HorizontalTextAlignment="End"
VerticalOptions="CenterAndExpand"
TextColor="{Binding SubLabelColor}"
StyleClass="list-sub" />
</controls:ExtendedStackLayout>
</DataTemplate>
<pages:SettingsPageListItemSelector
@@ -44,35 +42,32 @@
</ResourceDictionary>
</ContentPage.Resources>
<ListView
<controls:ExtendedCollectionView
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
HasUnevenRows="True"
RowHeight="-1"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGroupingEnabled="True"
ItemSelected="RowSelected"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<ListView.GroupHeaderTemplate>
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:SettingsPageListGroup">
<ViewCell>
<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
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>
</ViewCell>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</ListView>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</pages:BaseContentPage>

View File

@@ -1,7 +1,9 @@
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Utilities;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Controls;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -41,14 +43,14 @@ namespace Bit.App.Pages
return base.OnBackButtonPressed();
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (!(e.SelectedItem is SettingsPageListItem item))
if (!(e.CurrentSelection?.FirstOrDefault() is SettingsPageListItem item))
{
return;
}

View File

@@ -379,17 +379,23 @@ namespace Bit.App.Pages
}
var accountItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.ChangeMasterPassword },
new SettingsPageListItem { Name = AppResources.FingerprintPhrase },
new SettingsPageListItem { Name = AppResources.LogOut }
};
if (IncludeLinksWithSubscriptionInfo())
{
accountItems.Insert(0, new SettingsPageListItem { Name = AppResources.ChangeMasterPassword });
}
var toolsItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.ImportItems },
new SettingsPageListItem { Name = AppResources.ExportVault },
new SettingsPageListItem { Name = AppResources.ShareVault },
new SettingsPageListItem { Name = AppResources.WebVault }
new SettingsPageListItem { Name = AppResources.ExportVault }
};
if (IncludeLinksWithSubscriptionInfo())
{
toolsItems.Add(new SettingsPageListItem { Name = AppResources.ShareVault });
toolsItems.Add(new SettingsPageListItem { Name = AppResources.WebVault });
}
var otherItems = new List<SettingsPageListItem>
{
new SettingsPageListItem { Name = AppResources.Options },
@@ -408,6 +414,15 @@ namespace Bit.App.Pages
});
}
private bool IncludeLinksWithSubscriptionInfo()
{
if (Device.RuntimePlatform == Device.iOS)
{
return false;
}
return true;
}
private string GetVaultTimeoutActionFromKey(string key)
{
return _vaultTimeoutActions.FirstOrDefault(o => o.Key == key).Value;

View File

@@ -219,15 +219,40 @@
Text="{Binding Cipher.Card.CardholderName}"
StyleClass="box-value" />
</StackLayout>
<StackLayout StyleClass="box-row, box-row-input">
<Grid StyleClass="box-row, box-row-input">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n Number}"
StyleClass="box-label" />
<Entry
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<controls:MonoEntry
x:Name="_cardNumberEntry"
Text="{Binding Cipher.Card.Number}"
StyleClass="box-value" />
</StackLayout>
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0"
Keyboard="Numeric"
IsPassword="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}"
IsSpellCheckEnabled="False"
IsTextPredictionEnabled="False" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowCardNumberIcon}"
Command="{Binding ToggleCardNumberCommand}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
</Grid>
<StackLayout StyleClass="box-row, box-row-input">
<Label
Text="{u:I18n Brand}"
@@ -530,6 +555,24 @@
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n PasswordPrompt}"
StyleClass="box-label-regular" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf29c;"
Command="{Binding PasswordPromptHelpCommand}"
TextColor="{StaticResource MutedColor}"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ToggleVisibility}"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding PasswordPrompt}"
Toggled="PasswordPrompt_Toggled"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
<StackLayout StyleClass="box">
@@ -667,7 +710,10 @@
</StackLayout>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
<controls:RepeaterView ItemsSource="{Binding Collections}" IsVisible="{Binding HasCollections}">
<controls:RepeaterView
x:Name="_collectionsRepeaterView"
ItemsSource="{Binding Collections}"
IsVisible="{Binding HasCollections}">
<controls:RepeaterView.ItemTemplate>
<DataTemplate x:DataType="pages:CollectionViewModel">
<StackLayout Spacing="0" Padding="0">

View File

@@ -20,6 +20,7 @@ namespace Bit.App.Pages
private readonly AppOptions _appOptions;
private readonly IStorageService _storageService;
private readonly IDeviceActionService _deviceActionService;
private readonly IVaultTimeoutService _vaultTimeoutService;
private AddEditPageViewModel _vm;
private bool _fromAutofill;
@@ -38,6 +39,7 @@ namespace Bit.App.Pages
{
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
_appOptions = appOptions;
_fromAutofill = fromAutofill;
FromAutofillFramework = _appOptions?.FromAutofillFramework ?? false;
@@ -47,6 +49,7 @@ namespace Bit.App.Pages
_vm.CipherId = cipherId;
_vm.FolderId = folderId == "none" ? null : folderId;
_vm.CollectionIds = collectionId != null ? new HashSet<string>(new List<string> { collectionId }) : null;
_vm.CollectionsRepeaterView = _collectionsRepeaterView;
_vm.Type = type;
_vm.DefaultName = name ?? appOptions?.SaveName;
_vm.DefaultUri = uri ?? appOptions?.Uri;
@@ -144,6 +147,14 @@ namespace Bit.App.Pages
protected override async void OnAppearing()
{
base.OnAppearing();
if (!await AppHelpers.IsVaultTimeoutImmediateAsync())
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
}
if (await _vaultTimeoutService.IsLockedAsync())
{
return;
}
await LoadOnAppearedAsync(_scrollView, true, async () =>
{
var success = await _vm.LoadAsync(_appOptions);
@@ -158,6 +169,7 @@ namespace Bit.App.Pages
{
RequestFocus(_nameEntry);
}
_scrollView.Scrolled += (sender, args) => _vm.HandleScroll();
});
}
@@ -376,5 +388,10 @@ namespace Bit.App.Pages
}
}
}
private void PasswordPrompt_Toggled(object sender, ToggledEventArgs e)
{
_vm.Cipher.Reprompt = e.Value ? CipherRepromptType.Password : CipherRepromptType.None;
}
}
}

View File

@@ -1,4 +1,5 @@
using Bit.App.Abstractions;
using System;
using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.Core.Abstractions;
@@ -9,6 +10,7 @@ using Bit.Core.Utilities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Controls;
using Xamarin.Forms;
using View = Xamarin.Forms.View;
@@ -29,6 +31,7 @@ namespace Bit.App.Pages
private CipherView _cipher;
private bool _showNotesSeparator;
private bool _showPassword;
private bool _showCardNumber;
private bool _showCardCode;
private int _typeSelectedIndex;
private int _cardBrandSelectedIndex;
@@ -38,6 +41,7 @@ namespace Bit.App.Pages
private int _ownershipSelectedIndex;
private bool _hasCollections;
private string _previousCipherId;
private DateTime _lastHandledScrollTime;
private List<Core.Models.View.CollectionView> _writeableCollections;
private string[] _additionalCipherProperties = new string[]
{
@@ -82,10 +86,12 @@ namespace Bit.App.Pages
_policyService = ServiceContainer.Resolve<IPolicyService>("policyService");
GeneratePasswordCommand = new Command(GeneratePassword);
TogglePasswordCommand = new Command(TogglePassword);
ToggleCardNumberCommand = new Command(ToggleCardNumber);
ToggleCardCodeCommand = new Command(ToggleCardCode);
CheckPasswordCommand = new Command(CheckPasswordAsync);
UriOptionsCommand = new Command<LoginUriView>(UriOptions);
FieldOptionsCommand = new Command<AddEditPageFieldViewModel>(FieldOptions);
PasswordPromptHelpCommand = new Command(PasswordPromptHelp);
Uris = new ExtendedObservableCollection<LoginUriView>();
Fields = new ExtendedObservableCollection<AddEditPageFieldViewModel>();
Collections = new ExtendedObservableCollection<CollectionViewModel>();
@@ -141,10 +147,12 @@ namespace Bit.App.Pages
public Command GeneratePasswordCommand { get; set; }
public Command TogglePasswordCommand { get; set; }
public Command ToggleCardNumberCommand { get; set; }
public Command ToggleCardCodeCommand { get; set; }
public Command CheckPasswordCommand { get; set; }
public Command UriOptionsCommand { get; set; }
public Command FieldOptionsCommand { get; set; }
public Command PasswordPromptHelpCommand { get; set; }
public string CipherId { get; set; }
public string OrganizationId { get; set; }
public string FolderId { get; set; }
@@ -161,6 +169,7 @@ namespace Bit.App.Pages
public ExtendedObservableCollection<LoginUriView> Uris { get; set; }
public ExtendedObservableCollection<AddEditPageFieldViewModel> Fields { get; set; }
public ExtendedObservableCollection<CollectionViewModel> Collections { get; set; }
public RepeaterView CollectionsRepeaterView { get; set; }
public int TypeSelectedIndex
{
get => _typeSelectedIndex;
@@ -246,6 +255,15 @@ namespace Bit.App.Pages
nameof(ShowPasswordIcon)
});
}
public bool ShowCardNumber
{
get => _showCardNumber;
set => SetProperty(ref _showCardNumber, value,
additionalPropertyNames: new string[]
{
nameof(ShowCardNumberIcon)
});
}
public bool ShowCardCode
{
get => _showCardCode;
@@ -277,10 +295,12 @@ namespace Bit.App.Pages
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 int PasswordFieldColSpan => Cipher.ViewPassword ? 1 : 4;
public int TotpColumnSpan => Cipher.ViewPassword ? 1 : 2;
public bool AllowPersonal { get; set; }
public bool PasswordPrompt => Cipher.Reprompt != CipherRepromptType.None;
public void Init()
{
@@ -691,6 +711,16 @@ namespace Bit.App.Pages
}
}
public void ToggleCardNumber()
{
ShowCardNumber = !ShowCardNumber;
if (EditMode && ShowCardNumber)
{
var task = _eventService.CollectAsync(
Core.Enums.EventType.Cipher_ClientToggledCardNumberVisible, CipherId);
}
}
public void ToggleCardCode()
{
ShowCardCode = !ShowCardCode;
@@ -717,6 +747,11 @@ namespace Bit.App.Pages
}
}
public void PasswordPromptHelp()
{
_platformUtilsService.LaunchUri("https://bitwarden.com/help/article/managing-items/#protect-individual-items");
}
private void TypeChanged()
{
if (Cipher != null && TypeSelectedIndex > -1)
@@ -769,13 +804,30 @@ namespace Bit.App.Pages
{
var cols = _writeableCollections.Where(c => c.OrganizationId == Cipher.OrganizationId)
.Select(c => new CollectionViewModel { Collection = c }).ToList();
HasCollections = cols.Any();
Collections.ResetWithRange(cols);
Collections = new ExtendedObservableCollection<CollectionViewModel>(cols);
}
else
{
HasCollections = false;
Collections.ResetWithRange(new List<CollectionViewModel>());
Collections = new ExtendedObservableCollection<CollectionViewModel>(new List<CollectionViewModel>());
}
HasCollections = Collections.Any();
}
public void HandleScroll()
{
// workaround for https://github.com/xamarin/Xamarin.Forms/issues/13607
// required for org ownership/collections to render properly in XF4.5+
if (!HasCollections ||
EditMode ||
(DateTime.Now - _lastHandledScrollTime < TimeSpan.FromMilliseconds(200)))
{
return;
}
CollectionsRepeaterView.ItemsSource = Collections;
_lastHandledScrollTime = DateTime.Now;
}
private void TriggerCipherChanged()

View File

@@ -47,40 +47,35 @@
Clicked="AddButton_Clicked"></Button>
</StackLayout>
<controls:ExtendedListView
<controls:ExtendedCollectionView
IsVisible="{Binding ShowList}"
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGroupingEnabled="True"
ItemSelected="RowSelected"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
<ListView.GroupHeaderTemplate>
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<ViewCell>
<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
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>
</ViewCell>
</StackLayout>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</controls:ExtendedListView>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -4,7 +4,10 @@ using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using System;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Controls;
using Bit.App.Utilities;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -13,6 +16,7 @@ namespace Bit.App.Pages
{
private readonly AppOptions _appOptions;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IVaultTimeoutService _vaultTimeoutService;
private AutofillCiphersPageViewModel _vm;
@@ -25,11 +29,20 @@ namespace Bit.App.Pages
_vm.Init(appOptions);
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_vaultTimeoutService = ServiceContainer.Resolve<IVaultTimeoutService>("vaultTimeoutService");
}
protected async override void OnAppearing()
{
base.OnAppearing();
if (!await AppHelpers.IsVaultTimeoutImmediateAsync())
{
await _vaultTimeoutService.CheckVaultTimeoutAsync();
}
if (await _vaultTimeoutService.IsLockedAsync())
{
return;
}
await LoadOnAppearedAsync(_mainLayout, false, async () =>
{
try
@@ -44,14 +57,23 @@ namespace Bit.App.Pages
}, _mainContent);
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
protected override bool OnBackButtonPressed()
{
((ListView)sender).SelectedItem = null;
if (Device.RuntimePlatform == Device.Android)
{
_appOptions.Uri = null;
}
return base.OnBackButtonPressed();
}
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (e.SelectedItem is GroupingsPageListItem item && item.Cipher != null)
if (e.CurrentSelection?.FirstOrDefault() is GroupingsPageListItem item && item.Cipher != null)
{
await _vm.SelectCipherAsync(item.Cipher, item.FuzzyAutofill);
}

View File

@@ -23,6 +23,7 @@ namespace Bit.App.Pages
private readonly IDeviceActionService _deviceActionService;
private readonly ICipherService _cipherService;
private readonly IStateService _stateService;
private readonly IPasswordRepromptService _passwordRepromptService;
private AppOptions _appOptions;
private bool _showList;
@@ -35,6 +36,7 @@ namespace Bit.App.Pages
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
GroupedItems = new ExtendedObservableCollection<GroupingsPageListGroup>();
CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync);
@@ -118,10 +120,14 @@ namespace Bit.App.Pages
}
if (_deviceActionService.SystemMajorVersion() < 21)
{
await AppHelpers.CipherListOptions(Page, cipher);
await AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService);
}
else
{
if (cipher.Reprompt != CipherRepromptType.None && !await _passwordRepromptService.ShowPasswordPromptAsync())
{
return;
}
var autofillResponse = AppResources.Yes;
if (fuzzy)
{
@@ -175,7 +181,7 @@ namespace Bit.App.Pages
{
if ((Page as BaseContentPage).DoOnce())
{
await AppHelpers.CipherListOptions(Page, cipher);
await AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService);
}
}
}

View File

@@ -60,15 +60,14 @@
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center" />
<ListView x:Name="_listView"
<controls:ExtendedCollectionView
IsVisible="{Binding ShowList}"
ItemsSource="{Binding Ciphers}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
ItemSelected="RowSelected"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<ListView.ItemTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="views:CipherView">
<controls:CipherViewCell
Cipher="{Binding .}"
@@ -76,8 +75,8 @@
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}"
/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</CollectionView.ItemTemplate>
</controls:ExtendedCollectionView>
</StackLayout>
</pages:BaseContentPage>

View File

@@ -3,6 +3,8 @@ using Bit.App.Resources;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using System;
using System.Linq;
using Bit.App.Controls;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -119,15 +121,15 @@ namespace Bit.App.Pages
}
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (e.SelectedItem is CipherView cipher)
if (e.CurrentSelection?.FirstOrDefault() is CipherView cipher)
{
await _vm.SelectCipherAsync(cipher);
}

View File

@@ -22,6 +22,7 @@ namespace Bit.App.Pages
private readonly ISearchService _searchService;
private readonly IDeviceActionService _deviceActionService;
private readonly IStateService _stateService;
private readonly IPasswordRepromptService _passwordRepromptService;
private CancellationTokenSource _searchCancellationTokenSource;
private bool _showNoData;
@@ -35,6 +36,7 @@ namespace Bit.App.Pages
_searchService = ServiceContainer.Resolve<ISearchService>("searchService");
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
Ciphers = new ExtendedObservableCollection<CipherView>();
CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync);
@@ -182,7 +184,7 @@ namespace Bit.App.Pages
}
if (_deviceActionService.SystemMajorVersion() < 21)
{
await Utilities.AppHelpers.CipherListOptions(Page, cipher);
await Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService);
}
else
{
@@ -195,7 +197,7 @@ namespace Bit.App.Pages
{
if ((Page as BaseContentPage).DoOnce())
{
await Utilities.AppHelpers.CipherListOptions(Page, cipher);
await Utilities.AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService);
}
}
}

View File

@@ -1,14 +1,14 @@
<?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.GroupingsPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:effects="clr-namespace:Bit.App.Effects"
xmlns:controls="clr-namespace:Bit.App.Controls"
x:DataType="pages:GroupingsPageViewModel"
Title="{Binding PageTitle}"
x:Name="_page">
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.GroupingsPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:effects="clr-namespace:Bit.App.Effects"
xmlns:controls="clr-namespace:Bit.App.Controls"
x:DataType="pages:GroupingsPageViewModel"
Title="{Binding PageTitle}"
x:Name="_page">
<ContentPage.BindingContext>
<pages:GroupingsPageViewModel />
@@ -45,29 +45,27 @@
<DataTemplate x:Key="groupTemplate"
x:DataType="pages:GroupingsPageListItem">
<ViewCell>
<StackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform">
<controls:FaLabel.Effects>
<effects:FixedSizeEffect />
</controls:FaLabel.Effects>
</controls:FaLabel>
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub"/>
</StackLayout>
</ViewCell>
<controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform">
<controls:FaLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start"
VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform">
<controls:FaLabel.Effects>
<effects:FixedSizeEffect />
</controls:FaLabel.Effects>
</controls:FaLabel>
<Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
StyleClass="list-title"/>
<Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End"
VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End"
StyleClass="list-sub"/>
</controls:ExtendedStackLayout>
</DataTemplate>
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
@@ -89,27 +87,21 @@
IsVisible="{Binding ShowAddCipherButton}"></Button>
</StackLayout>
<controls:ExtendedListView
x:Name="_listView"
<RefreshView
IsVisible="{Binding ShowList}"
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
HasUnevenRows="True"
RowHeight="-1"
RefreshCommand="{Binding RefreshCommand}"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding Refreshing}"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGroupingEnabled="True"
ItemSelected="RowSelected"
StyleClass="list, list-platform">
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
Command="{Binding RefreshCommand}">
<controls:ExtendedCollectionView
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
<ListView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<ViewCell>
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
@@ -126,10 +118,10 @@
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</controls:ExtendedListView>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</RefreshView>
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -1,5 +1,4 @@
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Models;
using Bit.App.Resources;
using Bit.Core;
@@ -9,6 +8,7 @@ using Bit.Core.Utilities;
using System;
using System.Linq;
using System.Threading.Tasks;
using Bit.App.Controls;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -33,7 +33,6 @@ namespace Bit.App.Pages
{
_pageName = string.Concat(nameof(GroupingsPage), "_", DateTime.UtcNow.Ticks);
InitializeComponent();
ListView = _listView;
SetActivityIndicator(_mainContent);
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
_syncService = ServiceContainer.Resolve<ISyncService>("syncService");
@@ -73,8 +72,6 @@ namespace Bit.App.Pages
}
}
public ExtendedListView ListView { get; set; }
protected async override void OnAppearing()
{
base.OnAppearing();
@@ -197,14 +194,14 @@ namespace Bit.App.Pages
_vm.DisableRefreshing();
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
private async void RowSelected(object sender, SelectionChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
((ExtendedCollectionView)sender).SelectedItem = null;
if (!DoOnce())
{
return;
}
if (!(e.SelectedItem is GroupingsPageListItem item))
if (!(e.CurrentSelection?.FirstOrDefault() is GroupingsPageListItem item))
{
return;
}

View File

@@ -75,30 +75,30 @@ namespace Bit.App.Pages
}
else if (Folder != null)
{
_icon = Folder.Id == null ? "" : "";
_icon = Folder.Id == null ? "\uf115" : "\uf07c"; // fa-folder-open-o : fa-folder-open
}
else if (Collection != null)
{
_icon = "";
_icon = "\uf1b2"; // fa-cube
}
else if (Type != null)
{
switch (Type.Value)
{
case CipherType.Login:
_icon = "";
_icon = "\uf0ac"; // fa-globe
break;
case CipherType.SecureNote:
_icon = "";
_icon = "\uf24a"; // fa-sticky-note-o
break;
case CipherType.Card:
_icon = "";
_icon = "\uf09d"; // fa-credit-card
break;
case CipherType.Identity:
_icon = "";
_icon = "\uf2c3"; // fa-id-card-o
break;
default:
_icon = "";
_icon = "\uf0ac"; // fa-globe
break;
}
}

View File

@@ -46,6 +46,7 @@ namespace Bit.App.Pages
private readonly IMessagingService _messagingService;
private readonly IStateService _stateService;
private readonly IStorageService _storageService;
private readonly IPasswordRepromptService _passwordRepromptService;
public GroupingsPageViewModel()
{
@@ -60,6 +61,7 @@ namespace Bit.App.Pages
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_stateService = ServiceContainer.Resolve<IStateService>("stateService");
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
Loading = true;
PageTitle = AppResources.MyVault;
@@ -514,7 +516,7 @@ namespace Bit.App.Pages
{
if ((Page as BaseContentPage).DoOnce())
{
await AppHelpers.CipherListOptions(Page, cipher);
await AppHelpers.CipherListOptions(Page, cipher, _passwordRepromptService);
}
}
}

View File

@@ -34,57 +34,53 @@
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"></Label>
<ListView x:Name="_listView"
<controls:ExtendedCollectionView
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
ItemsSource="{Binding History}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
StyleClass="list, list-platform">
<ListView.ItemTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="views:PasswordHistoryView">
<ViewCell>
<Grid
StyleClass="list-row, list-row-platform"
Padding="10"
RowSpacing="0"
ColumnSpacing="10">
<Grid
StyleClass="list-row, list-row-platform"
Padding="10"
RowSpacing="0"
ColumnSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:MonoLabel LineBreakMode="CharacterWrap"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
TextType="Html"
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
<Label LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding LastUsedDate, Mode=OneWay, Converter={StaticResource dateTime}}" />
<controls:FaButton
StyleClass="list-row-button, list-row-button-platform"
Text="&#xf24d;"
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CopyPassword}" />
</Grid>
</ViewCell>
<controls:MonoLabel LineBreakMode="CharacterWrap"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
TextType="Html"
Text="{Binding Password, Mode=OneWay, Converter={StaticResource coloredPassword}}" />
<Label LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding LastUsedDate, Mode=OneWay, Converter={StaticResource dateTime}}" />
<controls:FaButton
StyleClass="list-row-button, list-row-button-platform"
Text="&#xf24d;"
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CopyPassword}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</CollectionView.ItemTemplate>
</controls:ExtendedCollectionView>
</StackLayout>
</pages:BaseContentPage>

View File

@@ -224,24 +224,41 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label
Text="{u:I18n Number}"
StyleClass="box-label"
Grid.Row="0"
Grid.Column="0" />
<Label
<controls:MonoLabel
Text="{Binding Cipher.Card.MaskedNumber, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0"
IsVisible="{Binding ShowCardNumber, Converter={StaticResource inverseBool}}" />
<controls:MonoLabel
Text="{Binding Cipher.Card.Number, Mode=OneWay}"
StyleClass="box-value"
Grid.Row="1"
Grid.Column="0" />
Grid.Column="0"
IsVisible="{Binding ShowCardNumber}" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="{Binding ShowCardNumberIcon}"
Command="{Binding ToggleCardNumberCommand}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n ToggleVisibility}" />
<controls:FaButton
StyleClass="box-row-button, box-row-button-platform"
Text="&#xf24d;"
Command="{Binding CopyCommand}"
CommandParameter="CardNumber"
Grid.Row="0"
Grid.Column="1"
Grid.Column="2"
Grid.RowSpan="2"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n CopyNumber}" />

View File

@@ -128,6 +128,10 @@ namespace Bit.App.Pages
}
else
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
await Navigation.PushModalAsync(new NavigationPage(new AddEditPage(_vm.CipherId)));
}
}
@@ -142,6 +146,10 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
var page = new AttachmentsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
@@ -151,6 +159,10 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
var page = new SharePage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
@@ -160,6 +172,10 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
if (await _vm.DeleteAsync())
{
await Navigation.PopModalAsync();
@@ -171,6 +187,10 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
var page = new CollectionsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
@@ -180,6 +200,10 @@ namespace Bit.App.Pages
{
if (DoOnce())
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
var page = new AddEditPage(_vm.CipherId, cloneMode: true, viewPage: this);
await Navigation.PushModalAsync(new NavigationPage(page));
}
@@ -205,6 +229,12 @@ namespace Bit.App.Pages
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel,
AppResources.Delete, options.ToArray());
if (!await _vm.PromptPasswordAsync())
{
return;
}
if (selection == AppResources.Delete)
{
if (await _vm.DeleteAsync())

View File

@@ -2,6 +2,7 @@
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
@@ -23,10 +24,12 @@ namespace Bit.App.Pages
private readonly IAuditService _auditService;
private readonly IMessagingService _messagingService;
private readonly IEventService _eventService;
private readonly IPasswordRepromptService _passwordRepromptService;
private CipherView _cipher;
private List<ViewPageFieldViewModel> _fields;
private bool _canAccessPremium;
private bool _showPassword;
private bool _showCardNumber;
private bool _showCardCode;
private string _totpCode;
private string _totpCodeFormatted;
@@ -36,6 +39,7 @@ namespace Bit.App.Pages
private string _previousCipherId;
private byte[] _attachmentData;
private string _attachmentFilename;
private bool _passwordReprompted;
public ViewPageViewModel()
{
@@ -47,11 +51,13 @@ namespace Bit.App.Pages
_auditService = ServiceContainer.Resolve<IAuditService>("auditService");
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
_eventService = ServiceContainer.Resolve<IEventService>("eventService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
CopyCommand = new Command<string>((id) => CopyAsync(id, null));
CopyUriCommand = new Command<LoginUriView>(CopyUri);
CopyFieldCommand = new Command<FieldView>(CopyField);
LaunchUriCommand = new Command<LoginUriView>(LaunchUri);
TogglePasswordCommand = new Command(TogglePassword);
ToggleCardNumberCommand = new Command(ToggleCardNumber);
ToggleCardCodeCommand = new Command(ToggleCardCode);
CheckPasswordCommand = new Command(CheckPasswordAsync);
DownloadAttachmentCommand = new Command<AttachmentView>(DownloadAttachmentAsync);
@@ -64,6 +70,7 @@ namespace Bit.App.Pages
public Command CopyFieldCommand { get; set; }
public Command LaunchUriCommand { get; set; }
public Command TogglePasswordCommand { get; set; }
public Command ToggleCardNumberCommand { get; set; }
public Command ToggleCardCodeCommand { get; set; }
public Command CheckPasswordCommand { get; set; }
public Command DownloadAttachmentCommand { get; set; }
@@ -109,6 +116,15 @@ namespace Bit.App.Pages
nameof(ShowPasswordIcon)
});
}
public bool ShowCardNumber
{
get => _showCardNumber;
set => SetProperty(ref _showCardNumber, value,
additionalPropertyNames: new string[]
{
nameof(ShowCardNumberIcon)
});
}
public bool ShowCardCode
{
get => _showCardCode;
@@ -188,6 +204,7 @@ namespace Bit.App.Pages
public bool ShowTotp => IsLogin && !string.IsNullOrWhiteSpace(Cipher.Login.Totp) &&
!string.IsNullOrWhiteSpace(TotpCodeFormatted);
public string ShowPasswordIcon => ShowPassword ? "" : "";
public string ShowCardNumberIcon => ShowCardNumber ? "" : "";
public string ShowCardCodeIcon => ShowCardCode ? "" : "";
public string TotpCodeFormatted
{
@@ -226,7 +243,7 @@ namespace Bit.App.Pages
}
Cipher = await cipher.DecryptAsync();
CanAccessPremium = await _userService.CanAccessPremiumAsync();
Fields = Cipher.Fields?.Select(f => new ViewPageFieldViewModel(Cipher, f)).ToList();
Fields = Cipher.Fields?.Select(f => new ViewPageFieldViewModel(this, Cipher, f)).ToList();
if (Cipher.Type == Core.Enums.CipherType.Login && !string.IsNullOrWhiteSpace(Cipher.Login.Totp) &&
(Cipher.OrganizationUseTotp || CanAccessPremium))
@@ -259,8 +276,13 @@ namespace Bit.App.Pages
_totpInterval = null;
}
public void TogglePassword()
public async void TogglePassword()
{
if (! await PromptPasswordAsync())
{
return;
}
ShowPassword = !ShowPassword;
if (ShowPassword)
{
@@ -268,8 +290,26 @@ namespace Bit.App.Pages
}
}
public void ToggleCardCode()
public async void ToggleCardNumber()
{
if (!await PromptPasswordAsync())
{
return;
}
ShowCardNumber = !ShowCardNumber;
if (ShowCardNumber)
{
var task = _eventService.CollectAsync(
Core.Enums.EventType.Cipher_ClientToggledCardNumberVisible, CipherId);
}
}
public async void ToggleCardCode()
{
if (!await PromptPasswordAsync())
{
return;
}
ShowCardCode = !ShowCardCode;
if (ShowCardCode)
{
@@ -474,6 +514,11 @@ namespace Bit.App.Pages
canOpenFile = false;
}
if (!await PromptPasswordAsync())
{
return;
}
await _deviceActionService.ShowLoadingAsync(AppResources.Downloading);
try
{
@@ -564,6 +609,11 @@ namespace Bit.App.Pages
private async void CopyAsync(string id, string text = null)
{
if (_passwordRepromptService.ProtectedFields.Contains(id) && !await PromptPasswordAsync())
{
return;
}
string name = null;
if (id == "LoginUsername")
{
@@ -638,16 +688,28 @@ namespace Bit.App.Pages
_platformUtilsService.LaunchUri(uri.LaunchUri);
}
}
internal async Task<bool> PromptPasswordAsync()
{
if (Cipher.Reprompt == CipherRepromptType.None || _passwordReprompted)
{
return true;
}
return _passwordReprompted = await _passwordRepromptService.ShowPasswordPromptAsync();
}
}
public class ViewPageFieldViewModel : ExtendedViewModel
{
private ViewPageViewModel _vm;
private FieldView _field;
private CipherView _cipher;
private bool _showHiddenValue;
public ViewPageFieldViewModel(CipherView cipher, FieldView field)
public ViewPageFieldViewModel(ViewPageViewModel vm, CipherView cipher, FieldView field)
{
_vm = vm;
_cipher = cipher;
Field = field;
ToggleHiddenValueCommand = new Command(ToggleHiddenValue);
@@ -688,8 +750,12 @@ namespace Bit.App.Pages
public bool ShowCopyButton => _field.Type != Core.Enums.FieldType.Boolean &&
!string.IsNullOrWhiteSpace(_field.Value) && !(IsHiddenType && !_cipher.ViewPassword);
public void ToggleHiddenValue()
public async void ToggleHiddenValue()
{
if (!await _vm.PromptPasswordAsync())
{
return;
}
ShowHiddenValue = !ShowHiddenValue;
if (ShowHiddenValue)
{

View File

@@ -1,7 +1,6 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -10,7 +9,6 @@
namespace Bit.App.Resources {
using System;
using System.Reflection;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
@@ -3371,6 +3369,12 @@ namespace Bit.App.Resources {
}
}
public static string AddASend {
get {
return ResourceManager.GetString("AddASend", resourceCulture);
}
}
public static string CopyLink {
get {
return ResourceManager.GetString("CopyLink", resourceCulture);
@@ -3508,5 +3512,25 @@ namespace Bit.App.Resources {
return ResourceManager.GetString("SendFileEmailVerificationRequired", resourceCulture);
}
}
public static string PasswordPrompt
{
get
{
return ResourceManager.GetString("PasswordPrompt", resourceCulture);
}
}
public static string PasswordConfirmation
{
get
{
return ResourceManager.GetString("PasswordConfirmation", resourceCulture);
}
}public static string PasswordConfirmationDesc
{
get
{
return ResourceManager.GetString("PasswordConfirmationDesc", resourceCulture);
}
}
}
}

View File

@@ -1901,7 +1901,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>There are no Sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1972,4 +1976,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1900,7 +1900,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>There are no Sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1971,4 +1975,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1603,10 +1603,10 @@
<value>Данните от трезора ви ще се изнесат в незащитен формат. Не го пращайте по незащитени канали като е-поща. Изтрийте файла незабавно след като свършите работата си с него.</value>
</data>
<data name="EncExportKeyWarning" xml:space="preserve">
<value>This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file.</value>
<value>При изнасяне данните се шифрират с ключа ви. Ако го смените, ще трябва наново да ги изнесете, защото няма да може да дешифрирате настоящия файл.</value>
</data>
<data name="EncExportAccountWarning" xml:space="preserve">
<value>Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account.</value>
<value>Ключовете за шифриране са уникални за всеки потребител, затова не може да внесете шифрирани данни от един потребител в регистрацията на друг.</value>
</data>
<data name="ExportVaultConfirmationTitle" xml:space="preserve">
<value>Потвърждаване на изнасянето на трезора</value>
@@ -1802,173 +1802,201 @@
<value>Политика от някоя организация влияе на вариантите за собственост.</value>
</data>
<data name="Send" xml:space="preserve">
<value>Send</value>
<value>Изпращане</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AllSends" xml:space="preserve">
<value>All Sends</value>
<value>Всички изпращания</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Sends" xml:space="preserve">
<value>Sends</value>
<value>Изпращания</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NameInfo" xml:space="preserve">
<value>A friendly name to describe this Send.</value>
<value>Описателно име за това изпращане.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeText" xml:space="preserve">
<value>Text</value>
<value>Текст</value>
</data>
<data name="TypeTextInfo" xml:space="preserve">
<value>The text you want to send.</value>
<value>Текст за изпращане.</value>
</data>
<data name="HideTextByDefault" xml:space="preserve">
<value>When accessing the Send, hide the text by default</value>
<value>При достъп до изпращането стандартно текстът да се скрива</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeFile" xml:space="preserve">
<value>File</value>
<value>Файл</value>
</data>
<data name="TypeFileInfo" xml:space="preserve">
<value>The file you want to send.</value>
<value>Файл за изпращане.</value>
</data>
<data name="DeletionDate" xml:space="preserve">
<value>Deletion Date</value>
<value>Дата на изтриване</value>
</data>
<data name="DeletionTime" xml:space="preserve">
<value>Deletion Time</value>
<value>Време на изтриване</value>
</data>
<data name="DeletionDateInfo" xml:space="preserve">
<value>The Send will be permanently deleted on the specified date and time.</value>
<value>Изпращането ще бъде окончателно изтрито на зададената дата и време.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PendingDelete" xml:space="preserve">
<value>Pending deletion</value>
<value>Предстои изтриване</value>
</data>
<data name="ExpirationDate" xml:space="preserve">
<value>Expiration Date</value>
<value>Дата на валидност</value>
</data>
<data name="ExpirationTime" xml:space="preserve">
<value>Expiration Time</value>
<value>Време на валидност</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>If set, access to this Send will expire on the specified date and time.</value>
<value>При задаване — това изпращане ще се изключи на зададената дата и време.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
<value>Expired</value>
<value>Изтекъл</value>
</data>
<data name="MaximumAccessCount" xml:space="preserve">
<value>Maximum Access Count</value>
<value>Максимален брой достъпвания.</value>
</data>
<data name="MaximumAccessCountInfo" xml:space="preserve">
<value>If set, users will no longer be able to access this send once the maximum access count is reached.</value>
<value>При задаване — това изпращане ще се изключи след определен брой достъпвания.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="MaximumAccessCountReached" xml:space="preserve">
<value>Max access count reached</value>
<value>Достигнат е максималният брой достъпвания</value>
</data>
<data name="CurrentAccessCount" xml:space="preserve">
<value>Current Access Count</value>
<value>Текущ брой на достъпванията</value>
</data>
<data name="NewPassword" xml:space="preserve">
<value>New Password</value>
<value>Нова парола</value>
</data>
<data name="PasswordInfo" xml:space="preserve">
<value>Optionally require a password for users to access this Send.</value>
<value>Изискване на парола за достъп до това изпращане.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="RemovePassword" xml:space="preserve">
<value>Remove Password</value>
<value>Премахване на парола</value>
</data>
<data name="AreYouSureRemoveSendPassword" xml:space="preserve">
<value>Are you sure you want to remove the password?</value>
<value>Сигурни ли сте, че искате да премахнете паролата?</value>
</data>
<data name="RemovingSendPassword" xml:space="preserve">
<value>Removing password</value>
<value>Премахване на парола</value>
</data>
<data name="SendPasswordRemoved" xml:space="preserve">
<value>Password has been removed.</value>
<value>Паролата е премахната.</value>
</data>
<data name="NotesInfo" xml:space="preserve">
<value>Private notes about this Send.</value>
<value>Скрити бележки за това изпращане.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSend" xml:space="preserve">
<value>Disable this Send so that no one can access it.</value>
<value>Пълно спиране на това изпращане — никой няма да има достъп.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>Няма изпращания.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copy Link</value>
<value>Копиране на връзката</value>
</data>
<data name="ShareLink" xml:space="preserve">
<value>Share Link</value>
<value>Споделяне на връзката</value>
</data>
<data name="SendLink" xml:space="preserve">
<value>Send link</value>
<value>Изпращане на връзката</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SearchSends" xml:space="preserve">
<value>Search Sends</value>
<value>Търсене в изпратените</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="EditSend" xml:space="preserve">
<value>Edit Send</value>
<value>Редактиране на изпращане</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddSend" xml:space="preserve">
<value>Add Send</value>
<value>Добавяне на изпращане</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AreYouSureDeleteSend" xml:space="preserve">
<value>Are you sure you want to delete this Send?</value>
<value>Сигурни ли сте, че искате да изтриете това изпращане?</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDeleted" xml:space="preserve">
<value>Send has been deleted.</value>
<value>Изпратеното е изтрито.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendUpdated" xml:space="preserve">
<value>Send updated.</value>
<value>Изпратеното е редактирано.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NewSendCreated" xml:space="preserve">
<value>New send created.</value>
<value>Създадено е ново изпращане.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="OneDay" xml:space="preserve">
<value>1 day</value>
<value>1 ден</value>
</data>
<data name="TwoDays" xml:space="preserve">
<value>2 days</value>
<value>2 дни</value>
</data>
<data name="ThreeDays" xml:space="preserve">
<value>3 days</value>
<value>3 дни</value>
</data>
<data name="SevenDays" xml:space="preserve">
<value>7 days</value>
<value>7 дни</value>
</data>
<data name="ThirtyDays" xml:space="preserve">
<value>30 days</value>
<value>30 дни</value>
</data>
<data name="Custom" xml:space="preserve">
<value>Custom</value>
<value>По избор</value>
</data>
<data name="ShareOnSave" xml:space="preserve">
<value>Share this Send upon save.</value>
<value>Споделяне на изпратеното при запис.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDisabledWarning" xml:space="preserve">
<value>Due to an enterprise policy, you are only able to delete an existing Send.</value>
<value>Поради политика на организация, може само да изтривате съществуващи изпращания.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AboutSend" xml:space="preserve">
<value>About Send</value>
<value>Относно изпращането</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Скриване на е-пощата ми от получателите.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Поне една политика на организация влияе на настройките за изпращане.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Безплатните регистрации могат да споделят само текст. Необходим е платен абонамент, за да можете да изпращате файлове.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Трябва да потвърдите е-пощата си, за да можете да изпращате файлове.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1901,7 +1901,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>There are no Sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1972,4 +1976,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

File diff suppressed because it is too large Load Diff

View File

@@ -1903,6 +1903,10 @@
<value>No hi ha cap enviament al vostre compte.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copia l'enllaç</value>
</data>
@@ -1971,4 +1975,28 @@
<value>Quant a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Amagueu la meua adreça de correu electrònic als destinataris.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Una o més polítiques d'organització afecten les vostres opcions del Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Els comptes gratuïts només es poden compartir text. Cal utilitzar una subscripció premium per utilitzar fitxers amb Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Heu de verificar el vostre correu electrònic per utilitzar aquesta característica.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1814,7 +1814,7 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NameInfo" xml:space="preserve">
<value>A friendly name to describe this Send.</value>
<value>Přátelský název pro popis tohoto Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeText" xml:space="preserve">
@@ -1840,7 +1840,7 @@
<value>Čas odstranění</value>
</data>
<data name="DeletionDateInfo" xml:space="preserve">
<value>The Send will be permanently deleted on the specified date and time.</value>
<value>Tento Send bude trvale smazán v určený datum a čas.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PendingDelete" xml:space="preserve">
@@ -1853,7 +1853,7 @@
<value>Čas expirace</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>Je-li nastaveno, přístup k tomuto Send vyprší k danému datumu a času.</value>
<value>Je-li nastaveno, přístup k tomuto Send vyprší v daný datum a čas.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
@@ -1876,7 +1876,7 @@
<value>Nové heslo</value>
</data>
<data name="PasswordInfo" xml:space="preserve">
<value>Volitelně vyžaduje heslo pro přístup k tomuto Send.</value>
<value>Volitelně vyžadovat heslo pro přístup k tomuto Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="RemovePassword" xml:space="preserve">
@@ -1896,11 +1896,15 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSend" xml:space="preserve">
<value>Disable this Send so that no one can access it.</value>
<value>Zakažte tento Send, aby k němu nikdo neměl přístup.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>Ve vašem účtu nejsou žádné Sends.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1910,7 +1914,7 @@
<value>Sdílet odkaz</value>
</data>
<data name="SendLink" xml:space="preserve">
<value>Odeslat odkaz</value>
<value>Odkaz tohoto Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SearchSends" xml:space="preserve">
@@ -1960,15 +1964,39 @@
<value>Vlastní</value>
</data>
<data name="ShareOnSave" xml:space="preserve">
<value>Share this Send upon save.</value>
<value>Sdílet tento Send po uložení.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDisabledWarning" xml:space="preserve">
<value>Due to an enterprise policy, you are only able to delete an existing Send.</value>
<value>Kvůli zásadám podniku můžete odstranit pouze existující Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AboutSend" xml:space="preserve">
<value>About Send</value>
<value>O Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Skrýt mou e-mailovou adresu před příjemci.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Jedna nebo více zásad organizace ovlivňuje nastavení Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Bezplatné účty jsou omezeny pouze na sdílení textu. K používání souborů pomocí Send je vyžadováno prémiové členství.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>K využívání souborů s pomocí Send je zapotřebí ověření vašeho e-mailu.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1603,7 +1603,7 @@
<value>Denne eksport indeholder dine boksdata i en ukrypteret form. Du bør ikke gemme eller sende den eksporterede fil via usikre kanaler (f.eks. e-mail). Slet den straks efter at du er færdig med at bruge den.</value>
</data>
<data name="EncExportKeyWarning" xml:space="preserve">
<value>Denne eksport krypterer dine data vha. din kontos krypteringsnøgle. Roterer du på et tidspunkt denne kontokrypteringsnøgle, skal du eksportere igen, da du ikke vil kunne dekryptere denne eksportfil.</value>
<value>Denne eksport krypterer dine data vha. din kontos krypteringsnøgle. Roterer du på et tidspunkt denne krypteringsnøgle, skal du eksportere igen, da du ikke vil kunne dekryptere denne eksportfil.</value>
</data>
<data name="EncExportAccountWarning" xml:space="preserve">
<value>Kontokrypteringsnøgler er unikke for hver Bitwarden-brugerkonto, så du kan ikke importere en krypteret eksport til en anden konto.</value>
@@ -1831,7 +1831,7 @@
<value>Fil</value>
</data>
<data name="TypeFileInfo" xml:space="preserve">
<value>Filen, du vil sende.</value>
<value>Den fil, du vil sende.</value>
</data>
<data name="DeletionDate" xml:space="preserve">
<value>Sletningsdato</value>
@@ -1840,7 +1840,7 @@
<value>Sletningstidspunkt</value>
</data>
<data name="DeletionDateInfo" xml:space="preserve">
<value>Send'en slettes permanent på angivne dato og tidspunkt.</value>
<value>Send'en slettes permanent på den angivne dato og tid.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PendingDelete" xml:space="preserve">
@@ -1853,21 +1853,21 @@
<value>Udløbstidspunkt</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>Hvis opsat, udløber adgangen til denne Send angivne dato og tidspunkt.</value>
<value>Hvis angivet, vil adgangen til denne Send udløbe på den angivne dato og tidspunkt.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
<value>Udløbet</value>
</data>
<data name="MaximumAccessCount" xml:space="preserve">
<value>Maks. antal tilgange</value>
<value>Maksimalt antal tilgange</value>
</data>
<data name="MaximumAccessCountInfo" xml:space="preserve">
<value>Hvis opsat, vil brugere ikke længere kunne tilgå denne Send, når maks. adgangsantal er nået.</value>
<value>Hvis opsat, vil brugere ikke længere kunne tilgå denne Send, når det maksimale adgangsantal er nået.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="MaximumAccessCountReached" xml:space="preserve">
<value>Maks. adgangsantal nået</value>
<value>Maksimalt adgangsantal nået</value>
</data>
<data name="CurrentAccessCount" xml:space="preserve">
<value>Aktuelt antal tilgange</value>
@@ -1883,16 +1883,16 @@
<value>Fjern adgangskode</value>
</data>
<data name="AreYouSureRemoveSendPassword" xml:space="preserve">
<value>Sikker på, at du vil fjerne adgangskoden?</value>
<value>Er du sikker på, at du vil fjerne adgangskoden?</value>
</data>
<data name="RemovingSendPassword" xml:space="preserve">
<value>Fjerner adgangskode</value>
</data>
<data name="SendPasswordRemoved" xml:space="preserve">
<value>Adgangskode er fjernet</value>
<value>Adgangskoden er fjernet.</value>
</data>
<data name="NotesInfo" xml:space="preserve">
<value>Fortrolige notater om denne Send.</value>
<value>Private notater om denne Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSend" xml:space="preserve">
@@ -1903,6 +1903,10 @@
<value>Der er ingen Sends i din konto.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Kopiér link</value>
</data>
@@ -1914,7 +1918,7 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SearchSends" xml:space="preserve">
<value>Find Sends</value>
<value>Søg i Sends</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="EditSend" xml:space="preserve">
@@ -1926,11 +1930,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AreYouSureDeleteSend" xml:space="preserve">
<value>Sikker på, at du vil slette denne Send?</value>
<value>Er du sikker på, at du vil slette denne Send?</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDeleted" xml:space="preserve">
<value>Element er slettet.</value>
<value>Send er blevet slettet.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendUpdated" xml:space="preserve">
@@ -1971,4 +1975,28 @@
<value>Om Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Skjul min e-mailadresse for modtagere.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Én eller flere organisationspolitikker påvirker dine Send-valgmuligheder.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Gratis konti er begrænsede til tekstdeling alene. Et Premium-medlemskab kræves for a bruge filer med Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Du skal bekræfte din e-mail for brug af filer med Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1603,10 +1603,10 @@
<value>Dieser Export enthält deine Tresordaten in einem unverschlüsseltem Format. Du solltest sie nicht speichern oder über unsichere Kanäle (z. B. E-Mail) senden. Lösche sie sofort nach ihrer Verwendung.</value>
</data>
<data name="EncExportKeyWarning" xml:space="preserve">
<value>Dieser Export verschlüsselt Ihre Daten mit dem Verschlüsselungscode Ihres Kontos. Falls Sie Ihren Verschlüsselungscode erneuern, sollten Sie den Export erneut durchführen, da Sie die zuvor erstellte Datei ansonsten nicht mehr entschlüsseln können.</value>
<value>Dieser Export verschlüsselt deine Daten mit dem Verschlüsselungscode deines Kontos. Falls du deinen Verschlüsselungscode erneuerst, solltest du den Export erneut durchführen, da du die zuvor erstellte Datei ansonsten nicht mehr entschlüsseln kannst.</value>
</data>
<data name="EncExportAccountWarning" xml:space="preserve">
<value>Die Verschlüsselungscodes eines Kontos sind für jedes Bitwarden Benutzerkonto einzigartig, deshalb können Sie keinen verschlüsselten Export in ein anderes Konto importieren.</value>
<value>Die Verschlüsselungscodes eines Kontos sind für jedes Bitwarden Benutzerkonto einzigartig, deshalb kannst du keinen verschlüsselten Export in ein anderes Konto importieren.</value>
</data>
<data name="ExportVaultConfirmationTitle" xml:space="preserve">
<value>Tresor-Export bestätigen</value>
@@ -1821,17 +1821,17 @@
<value>Text</value>
</data>
<data name="TypeTextInfo" xml:space="preserve">
<value>Der Text, den Sie senden möchten.</value>
<value>Der Text, den du senden möchtest.</value>
</data>
<data name="HideTextByDefault" xml:space="preserve">
<value>Beim Zugriff auf dieses Send den Text standardmäßig ausblenden</value>
<value>Beim Zugriff auf diesen Send den Text standardmäßig ausblenden</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeFile" xml:space="preserve">
<value>Datei</value>
</data>
<data name="TypeFileInfo" xml:space="preserve">
<value>Die Datei, die Sie senden möchten.</value>
<value>Die Datei, die du senden möchtest.</value>
</data>
<data name="DeletionDate" xml:space="preserve">
<value>Löschdatum</value>
@@ -1850,10 +1850,10 @@
<value>Ablaufdatum</value>
</data>
<data name="ExpirationTime" xml:space="preserve">
<value>Verfallszeit</value>
<value>Ablaufzeit</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>Falls aktiviert, verfällt der Zugriff auf dieses Send am angegebenen Datum zur angegebenen Uhrzeit.</value>
<value>Falls aktiviert, verfällt der Zugriff auf diesen Send zur angegebenen Datum und Uhrzeit.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
@@ -1863,7 +1863,7 @@
<value>Maximale Zugriffsanzahl</value>
</data>
<data name="MaximumAccessCountInfo" xml:space="preserve">
<value>Falls aktiviert, können Benutzer nicht mehr auf dieses Send zugreifen, sobald die maximale Zugriffsanzahl erreicht ist.</value>
<value>Falls aktiviert, können Benutzer nicht mehr auf diesesn Send zugreifen, sobald die maximale Zugriffsanzahl erreicht ist.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="MaximumAccessCountReached" xml:space="preserve">
@@ -1883,7 +1883,7 @@
<value>Passwort entfernen</value>
</data>
<data name="AreYouSureRemoveSendPassword" xml:space="preserve">
<value>Sind Sie sicher, dass Sie das Passwort entfernen möchten?</value>
<value>Bist du sicher, dass du dieses Passwort entfernen möchtest?</value>
</data>
<data name="RemovingSendPassword" xml:space="preserve">
<value>Passwort wird entfernt</value>
@@ -1900,7 +1900,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>Es gibt keine Sends in Ihrem Konto.</value>
<value>Es gibt keine Sends in deinem Konto.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1926,7 +1930,7 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AreYouSureDeleteSend" xml:space="preserve">
<value>Sind Sie sicher, dass Sie dieses Send löschen möchten?</value>
<value>Bist du sicher, dass du dieses Send löschen möchtest?</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDeleted" xml:space="preserve">
@@ -1964,11 +1968,35 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDisabledWarning" xml:space="preserve">
<value>Aufgrund einer Unternehmensrichtlinie können Sie nur ein bestehendes Send löschen.</value>
<value>Aufgrund einer Unternehmensrichtlinie kannst du nur ein bestehendes Send löschen.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AboutSend" xml:space="preserve">
<value>Über Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Meine E-Mail-Adresse vor den Empfängern ausblenden.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Eine oder mehrere Organisationsrichtlinien beeinflussen deine Send Einstellungen.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Kostenlose Konten sind auf das Teilen von Texten beschränkt. Eine Premium-Mitgliedschaft ist erforderlich, um Dateien mit Send zu verwenden.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Du musst deine E-Mail verifizieren, um diese Funktion nutzen zu können.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1604,10 +1604,10 @@
<value>Αυτή η εξαγωγή περιέχει τα δεδομένα σε μη κρυπτογραφημένη μορφή. Δεν πρέπει να αποθηκεύετε ή να στείλετε το εξαγόμενο αρχείο μέσω μη ασφαλών τρόπων (όπως μέσω email). Διαγράψτε το αμέσως μόλις τελειώσετε με τη χρήση του.</value>
</data>
<data name="EncExportKeyWarning" xml:space="preserve">
<value>This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file.</value>
<value>Αυτή η εξαγωγή κρυπτογραφεί τα δεδομένα σας χρησιμοποιώντας το κλειδί κρυπτογράφησης του λογαριασμού σας. Εάν ποτέ περιστρέψετε το κλειδί κρυπτογράφησης του λογαριασμού σας, θα πρέπει να κάνετε εξαγωγή ξανά, καθώς δεν θα μπορείτε να αποκρυπτογραφήσετε αυτό το αρχείο εξαγωγής.</value>
</data>
<data name="EncExportAccountWarning" xml:space="preserve">
<value>Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account.</value>
<value>Τα κλειδιά κρυπτογράφησης λογαριασμού είναι μοναδικά για κάθε λογαριασμό χρήστη Bitwarden, οπότε δεν μπορείτε να εισάγετε μια κρυπτογραφημένη εξαγωγή σε διαφορετικό λογαριασμό.</value>
</data>
<data name="ExportVaultConfirmationTitle" xml:space="preserve">
<value>Επιβεβαίωση εξαγωγής Vault</value>
@@ -1807,7 +1807,7 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AllSends" xml:space="preserve">
<value>All Sends</value>
<value>Όλα τα Sends</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Sends" xml:space="preserve">
@@ -1815,161 +1815,189 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NameInfo" xml:space="preserve">
<value>A friendly name to describe this Send.</value>
<value>Ένα φιλικό όνομα για την περιγραφή αυτού του Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeText" xml:space="preserve">
<value>Text</value>
<value>Κείμενο</value>
</data>
<data name="TypeTextInfo" xml:space="preserve">
<value>The text you want to send.</value>
<value>Το κείμενο που θέλετε να στείλετε.</value>
</data>
<data name="HideTextByDefault" xml:space="preserve">
<value>When accessing the Send, hide the text by default</value>
<value>Κατά την πρόσβαση σε αυτό το Send, αποκρύψτε το κείμενο από προεπιλογή</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeFile" xml:space="preserve">
<value>File</value>
<value>Αρχείο</value>
</data>
<data name="TypeFileInfo" xml:space="preserve">
<value>The file you want to send.</value>
<value>Το αρχείο που θέλετε να στείλετε.</value>
</data>
<data name="DeletionDate" xml:space="preserve">
<value>Deletion Date</value>
<value>Ημερομηνία διαγραφής</value>
</data>
<data name="DeletionTime" xml:space="preserve">
<value>Deletion Time</value>
<value>Χρόνος Διαγραφής</value>
</data>
<data name="DeletionDateInfo" xml:space="preserve">
<value>The Send will be permanently deleted on the specified date and time.</value>
<value>Το Send θα διαγραφεί οριστικά την καθορισμένη ημερομηνία και ώρα.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PendingDelete" xml:space="preserve">
<value>Pending deletion</value>
<value>Εκκρεμεί διαγραφή</value>
</data>
<data name="ExpirationDate" xml:space="preserve">
<value>Expiration Date</value>
<value>Ημερομηνία Λήξης</value>
</data>
<data name="ExpirationTime" xml:space="preserve">
<value>Expiration Time</value>
<value>Χρόνος λήξης</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>If set, access to this Send will expire on the specified date and time.</value>
<value>Εάν οριστεί, η πρόσβαση σε αυτό το Send θα λήξει την καθορισμένη ημερομηνία και ώρα.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
<value>Expired</value>
<value>Έληξε</value>
</data>
<data name="MaximumAccessCount" xml:space="preserve">
<value>Maximum Access Count</value>
<value>Μέγιστος Αριθμός Πρόσβασης</value>
</data>
<data name="MaximumAccessCountInfo" xml:space="preserve">
<value>If set, users will no longer be able to access this send once the maximum access count is reached.</value>
<value>Εάν οριστεί, οι χρήστες δεν θα μπορούν πλέον να έχουν πρόσβαση σε αυτό το send μόλις επιτευχθεί ο μέγιστος αριθμός πρόσβασης.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="MaximumAccessCountReached" xml:space="preserve">
<value>Max access count reached</value>
<value>Φτάσατε στον μέγιστο αριθμό πρόσβασης</value>
</data>
<data name="CurrentAccessCount" xml:space="preserve">
<value>Current Access Count</value>
<value>Τρέχων Αριθμός Πρόσβασης</value>
</data>
<data name="NewPassword" xml:space="preserve">
<value>New Password</value>
<value>Νέος Κωδικός</value>
</data>
<data name="PasswordInfo" xml:space="preserve">
<value>Optionally require a password for users to access this Send.</value>
<value>Προαιρετικά απαιτείται κωδικός πρόσβασης για τους χρήστες για να έχουν πρόσβαση σε αυτό το Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="RemovePassword" xml:space="preserve">
<value>Remove Password</value>
<value>Αφαίρεση κωδικού</value>
</data>
<data name="AreYouSureRemoveSendPassword" xml:space="preserve">
<value>Are you sure you want to remove the password?</value>
<value>Είστε βέβαιοι ότι θέλετε να καταργήσετε τον κωδικό πρόσβασης;</value>
</data>
<data name="RemovingSendPassword" xml:space="preserve">
<value>Removing password</value>
<value>Αφαίρεση κωδικού...</value>
</data>
<data name="SendPasswordRemoved" xml:space="preserve">
<value>Password has been removed.</value>
<value>Ο κωδικός έχει αφαιρεθεί.</value>
</data>
<data name="NotesInfo" xml:space="preserve">
<value>Private notes about this Send.</value>
<value>Ιδιωτικές σημειώσεις σχετικά με αυτό το Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSend" xml:space="preserve">
<value>Disable this Send so that no one can access it.</value>
<value>Απενεργοποιήστε αυτό το Send έτσι ώστε κανείς να μην μπορεί να έχει πρόσβαση σε αυτό.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>Δεν υπάρχουν sends στο λογαριασμό σας.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copy Link</value>
<value>Αντιγραφή Συνδέσμου</value>
</data>
<data name="ShareLink" xml:space="preserve">
<value>Share Link</value>
<value>Κοινοποίηση Συνδέσμου</value>
</data>
<data name="SendLink" xml:space="preserve">
<value>Send link</value>
<value>Σύνδεσμος Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SearchSends" xml:space="preserve">
<value>Search Sends</value>
<value>Αναζήτηση Sends</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="EditSend" xml:space="preserve">
<value>Edit Send</value>
<value>Επεξεργασία Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddSend" xml:space="preserve">
<value>Add Send</value>
<value>Προσθήκη Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AreYouSureDeleteSend" xml:space="preserve">
<value>Are you sure you want to delete this Send?</value>
<value>Είστε βέβαιοι ότι θέλετε να διαγράψετε το Send;</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDeleted" xml:space="preserve">
<value>Send has been deleted.</value>
<value>Το send έχει διαγραφεί.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendUpdated" xml:space="preserve">
<value>Send updated.</value>
<value>Το send ενημερώθηκε.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NewSendCreated" xml:space="preserve">
<value>New send created.</value>
<value>Δημιουργήθηκε νέο send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="OneDay" xml:space="preserve">
<value>1 day</value>
<value>1 ημέρα</value>
</data>
<data name="TwoDays" xml:space="preserve">
<value>2 days</value>
<value>2 ημέρες</value>
</data>
<data name="ThreeDays" xml:space="preserve">
<value>3 days</value>
<value>3 ημέρες</value>
</data>
<data name="SevenDays" xml:space="preserve">
<value>7 days</value>
<value>7 ημέρες</value>
</data>
<data name="ThirtyDays" xml:space="preserve">
<value>30 days</value>
<value>30 ημέρες</value>
</data>
<data name="Custom" xml:space="preserve">
<value>Custom</value>
<value>Προσαρμοσμένο</value>
</data>
<data name="ShareOnSave" xml:space="preserve">
<value>Share this Send upon save.</value>
<value>Κοινοποιήστε αυτό το send κατά την αποθήκευση.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDisabledWarning" xml:space="preserve">
<value>Due to an enterprise policy, you are only able to delete an existing Send.</value>
<value>Λόγω μιας επιχειρηματικής πολιτικής, είστε σε θέση να διαγράψετε μόνο ένα υπάρχον Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AboutSend" xml:space="preserve">
<value>About Send</value>
<value>Σχετικά με το Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Απόκρυψη της διεύθυνσης email μου από τους παραλήπτες.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Μία ή περισσότερες οργανωτικές πολιτικές επηρεάζουν τις επιλογές send σας.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Οι δωρεάν λογαριασμοί περιορίζονται μόνο στην κοινή χρήση κειμένου. Μια premium συνδρομή απαιτείται για τη χρήση αρχείων με Αποστολή.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Πρέπει να επαληθεύσετε το email σας για να χρησιμοποιήσετε τα αρχεία με το send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1913,7 +1913,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>There are no Sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1984,4 +1988,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organisation policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1917,6 +1917,10 @@
<value>There are no sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copy Link</value>
</data>
@@ -1985,4 +1989,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1802,36 +1802,36 @@
<value>An organization policy is affecting your ownership options.</value>
</data>
<data name="Send" xml:space="preserve">
<value>Send</value>
<value>Envío</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AllSends" xml:space="preserve">
<value>All Sends</value>
<value>Todos los Envíos</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Sends" xml:space="preserve">
<value>Sends</value>
<value>Envíos</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NameInfo" xml:space="preserve">
<value>A friendly name to describe this Send.</value>
<value>Un nombre amigable para describir este Envío.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeText" xml:space="preserve">
<value>Text</value>
<value>Texto</value>
</data>
<data name="TypeTextInfo" xml:space="preserve">
<value>The text you want to send.</value>
<value>El texto que quieres enviar.</value>
</data>
<data name="HideTextByDefault" xml:space="preserve">
<value>When accessing the Send, hide the text by default</value>
<value>Al acceder a este Envío, ocultar este texto por defecto</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeFile" xml:space="preserve">
<value>File</value>
<value>Archivo</value>
</data>
<data name="TypeFileInfo" xml:space="preserve">
<value>The file you want to send.</value>
<value>El archivo que quieres enviar.</value>
</data>
<data name="DeletionDate" xml:space="preserve">
<value>Deletion Date</value>
@@ -1844,7 +1844,7 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PendingDelete" xml:space="preserve">
<value>Pending deletion</value>
<value>Eliminación pendiente</value>
</data>
<data name="ExpirationDate" xml:space="preserve">
<value>Expiration Date</value>
@@ -1873,7 +1873,7 @@
<value>Current Access Count</value>
</data>
<data name="NewPassword" xml:space="preserve">
<value>New Password</value>
<value>Nueva contraseña</value>
</data>
<data name="PasswordInfo" xml:space="preserve">
<value>Optionally require a password for users to access this Send.</value>
@@ -1892,75 +1892,79 @@
<value>Password has been removed.</value>
</data>
<data name="NotesInfo" xml:space="preserve">
<value>Private notes about this Send.</value>
<value>Notas privadas sobre este Envío.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSend" xml:space="preserve">
<value>Disable this Send so that no one can access it.</value>
<value>Desactivar este Envío para que nadie pueda acceder a él.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>No hay Envíos en tu cuenta.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copy Link</value>
<value>Copiar enlace</value>
</data>
<data name="ShareLink" xml:space="preserve">
<value>Share Link</value>
<value>Compartir enlace</value>
</data>
<data name="SendLink" xml:space="preserve">
<value>Send link</value>
<value>Enviar enlace</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SearchSends" xml:space="preserve">
<value>Search Sends</value>
<value>Buscar Envíos</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="EditSend" xml:space="preserve">
<value>Edit Send</value>
<value>Editar Envío</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddSend" xml:space="preserve">
<value>Add Send</value>
<value>Añadir Envío</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AreYouSureDeleteSend" xml:space="preserve">
<value>Are you sure you want to delete this Send?</value>
<value>¿Seguro que quieres eliminar este Envío?</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDeleted" xml:space="preserve">
<value>Send has been deleted.</value>
<value>El Envío se ha eliminado.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendUpdated" xml:space="preserve">
<value>Send updated.</value>
<value>Envío actualizado.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NewSendCreated" xml:space="preserve">
<value>New send created.</value>
<value>Nuevo Envío creado.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="OneDay" xml:space="preserve">
<value>1 day</value>
<value>1 día</value>
</data>
<data name="TwoDays" xml:space="preserve">
<value>2 days</value>
<value>2 días</value>
</data>
<data name="ThreeDays" xml:space="preserve">
<value>3 days</value>
<value>3 días</value>
</data>
<data name="SevenDays" xml:space="preserve">
<value>7 days</value>
<value>7 días</value>
</data>
<data name="ThirtyDays" xml:space="preserve">
<value>30 days</value>
<value>30 días</value>
</data>
<data name="Custom" xml:space="preserve">
<value>Custom</value>
</data>
<data name="ShareOnSave" xml:space="preserve">
<value>Share this Send upon save.</value>
<value>Compartir este Envío al guardarlo.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDisabledWarning" xml:space="preserve">
@@ -1971,4 +1975,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -363,7 +363,7 @@
<value>Kinnita sõrmejäljega</value>
</data>
<data name="VerifyMasterPassword" xml:space="preserve">
<value>Kinnita ülemparooliga</value>
<value>Autendi ülemparooliga</value>
</data>
<data name="VerifyPIN" xml:space="preserve">
<value>Kinnita PIN</value>
@@ -711,7 +711,7 @@
<value>Bitwardeni Veebihoidla</value>
</data>
<data name="Lost2FAApp" xml:space="preserve">
<value>Kaotasid autentiseerimise rakenduse?</value>
<value>Kaotasid autentimise rakenduse?</value>
</data>
<data name="Items" xml:space="preserve">
<value>Kirjet</value>
@@ -790,11 +790,11 @@
<comment>Message shown when trying to launch an app that does not exist on the user's device.</comment>
</data>
<data name="AuthenticatorAppTitle" xml:space="preserve">
<value>Autentiseerimise rakendus</value>
<value>Autentimise rakendus</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeApp" xml:space="preserve">
<value>Sisesta autentiseerimise rakendusest 6 kohaline number.</value>
<value>Sisesta autentimise rakendusest 6 kohaline number.</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeEmail" xml:space="preserve">
@@ -806,7 +806,7 @@
<comment>For 2FA whenever there are no available providers on this device.</comment>
</data>
<data name="NoTwoStepAvailable" xml:space="preserve">
<value>Sellel kontol on aktiveeritud kaheastmeline kinnitus. Siiski ei toeta ükski aktiveeritud kaheastmelise kinnitamise teenus seda konkreetset seadet. Palun kasuta ühilduvat seadet ja/või lisa uus kaheastmelise teenuse pakkuja, mis töötab rohkemates seadmetes (näiteks mõni autentiseerimise rakendus).</value>
<value>Sellel kontol on aktiveeritud kaheastmeline kinnitus. Siiski ei toeta ükski aktiveeritud kaheastmelise kinnitamise teenus seda konkreetset seadet. Palun kasuta ühilduvat seadet ja/või lisa uus kaheastmelise teenuse pakkuja, mis töötab rohkemates seadmetes (näiteks mõni autentimise rakendus).</value>
</data>
<data name="RecoveryCodeTitle" xml:space="preserve">
<value>Taastamise kood</value>
@@ -862,17 +862,17 @@
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data>
<data name="AuthenticatorKey" xml:space="preserve">
<value>Autentiseerimise võti (TOTP)</value>
<value>Autentimise võti (TOTP)</value>
</data>
<data name="VerificationCodeTotp" xml:space="preserve">
<value>Kinnituskood (TOTP)</value>
<comment>Totp code label</comment>
</data>
<data name="AuthenticatorKeyAdded" xml:space="preserve">
<value>Autentiseerimise võti on lisatud.</value>
<value>Autentimise võti on lisatud.</value>
</data>
<data name="AuthenticatorKeyReadError" xml:space="preserve">
<value>Autentiseerimise võtme lugemine nurjus.</value>
<value>Autentimise võtme lugemine nurjus.</value>
</data>
<data name="CameraInstructionBottom" xml:space="preserve">
<value>Skaneering toimub automaatselt.</value>
@@ -893,7 +893,7 @@
<value>Kopeeri TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>Kui sinu sisselogimise andmetele on juurde lisatud autentiseerimise võti, kopeeritakse TOTP kood automaattäite kasutamisel lõikepuhvrisse.</value>
<value>Kui sinu sisselogimise andmetele on juurde lisatud autentimise võti, kopeeritakse TOTP kood automaattäite kasutamisel lõikepuhvrisse.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Keela automaatne TOTP kopeerimine</value>
@@ -1853,7 +1853,7 @@
<value>Aegumise kellaaeg</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>Seadistamisel ei pääse sellele Sendile enam pärast määratud kuupäeva ligi.</value>
<value>Selle valimisel ei pääse sellele Sendile enam pärast määratud kuupäeva ligi.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
@@ -1863,7 +1863,7 @@
<value>Maksimaalne ligipääsude arv</value>
</data>
<data name="MaximumAccessCountInfo" xml:space="preserve">
<value>Seadistamisel ei saa kasutajad pärast maksimaalse ligipääsude arvu saavutamist sellele Sendile enam ligi.</value>
<value>Selle valimisel ei saa kasutajad pärast maksimaalse ligipääsude arvu saavutamist sellele Sendile enam ligi.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="MaximumAccessCountReached" xml:space="preserve">
@@ -1876,7 +1876,7 @@
<value>Uus Parool</value>
</data>
<data name="PasswordInfo" xml:space="preserve">
<value>Mittekohustuslik parooli küsimine, et Sendile ligi pääseda.</value>
<value>Soovi korral nõua parooli, millega Sendile ligi pääseb.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="RemovePassword" xml:space="preserve">
@@ -1903,8 +1903,12 @@
<value>Kontol pole ühtegi Sendi.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Kopeeri aadress</value>
<value>Kopeeri link</value>
</data>
<data name="ShareLink" xml:space="preserve">
<value>Jaga linki</value>
@@ -1968,7 +1972,31 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AboutSend" xml:space="preserve">
<value>Teave Sendist</value>
<value>Rohkem infot</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Ära näita saajatele minu e-posti aadressi.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Organisatsiooni seaded mõjutavad sinu Sendi sätteid.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Tasuta kontoga on võimalik saata ainult tekste. Failide saatmiseks on vajalik omada tasulist kontot.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Failide saatmiseks läbi Sendi pead kinnitama oma e-posti.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1903,6 +1903,10 @@
<value>هیچ ارسالی در حساب شما وجود ندارد.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>کپی پیوند</value>
</data>
@@ -1971,4 +1975,28 @@
<value>درباره ارسال</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>آدرس ایمیلم را از گیرندگان مخفی کن.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>یک یا چند سیاست سازمان بر گزینه های ارسال شما تأثیر می گذارد.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>حساب های رایگان فقط به اشتراک گذاری متن محدود می شوند. برای استفاده از پرونده های با Send عضویت Premium لازم است.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>برای استفاده از پرونده های با Send باید ایمیل خود را تأیید کنید.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1903,6 +1903,10 @@
<value>Tililläsi ei ole Sendejä.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Kopioi linkki</value>
</data>
@@ -1971,4 +1975,28 @@
<value>Tietoja Sendistä</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Piilota sähköpostiosoitteeni vastaanottajilta.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Yksi tai useampi organisaatiokäytäntö vaikuttaa Send-asetuksiisi.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Ilmaiset tilit on rajoitettu tekstin jakoon. Tiedostojen käyttö Sendeissä vaatii Premium-jäsenyyden.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Sinun on vahvistettava sähköpostiosoitteesi, jotta voit käyttää tiedostoja Sendeissä.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1903,6 +1903,10 @@
<value>Il ny a aucun Send dans votre compte.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copier le lien</value>
</data>
@@ -1971,4 +1975,28 @@
<value>À propos de Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Cacher mon adresse e-mail aux destinataires.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Une ou plusieurs politiques d'organisation affectent vos options Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Les comptes gratuits sont limités au partage de texte. Un abonnement premium est requis pour utiliser les fichiers avec Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Vous devez vérifier votre e-mail pour utiliser des fichiers avec Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1901,7 +1901,11 @@ Bitwarden בעזרת פתיחת חלון "הגדרות".</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>There are no Sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1972,4 +1976,28 @@ Bitwarden בעזרת פתיחת חלון "הגדרות".</value>
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -1902,7 +1902,11 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>There are no Sends in your account.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
@@ -1973,4 +1977,28 @@
<value>About Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Hide my email address from recipients.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>One or more organization policies are affecting your Send options.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Free accounts are restricted to sharing text only. A premium membership is required to use files with Send.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>You must verify your email to use files with Send. You can verify your email in the web vault.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

View File

@@ -257,7 +257,7 @@
<value>Neispravan PIN. Pokušaj ponovo.</value>
</data>
<data name="Launch" xml:space="preserve">
<value>Pokreni</value>
<value>Otvori web stranicu</value>
<comment>The button text that allows user to launch the website to their web browser.</comment>
</data>
<data name="LogIn" xml:space="preserve">
@@ -288,7 +288,7 @@
<comment>The title for the vault page.</comment>
</data>
<data name="Name" xml:space="preserve">
<value>Ime</value>
<value>Naziv</value>
<comment>Label for an entity name.</comment>
</data>
<data name="No" xml:space="preserve">
@@ -607,7 +607,7 @@
<value>Zadane postavke preuzete iz generatora lozinki glavne aplikacije Bitwarden.</value>
</data>
<data name="Options" xml:space="preserve">
<value>Mogućnosti</value>
<value>Opcije</value>
</data>
<data name="Other" xml:space="preserve">
<value>Ostalo</value>
@@ -679,7 +679,7 @@
<value>Sinkronizacija nije uspjela.</value>
</data>
<data name="SyncVaultNow" xml:space="preserve">
<value>Sinkronizirajte trezor sada</value>
<value>Sinkroniziraj trezor</value>
</data>
<data name="TouchID" xml:space="preserve">
<value>Touch ID</value>
@@ -731,7 +731,7 @@
<comment>This is used for the autofill service. ex. "Logins for twitter.com"</comment>
</data>
<data name="NoItemsForUri" xml:space="preserve">
<value>U tvom trezoru nema stavki za {0}.</value>
<value>U tvom trezoru nema stavki za {0}</value>
<comment>This is used for the autofill service. ex. "There are no items in your vault for twitter.com".</comment>
</data>
<data name="BitwardenAutofillServiceOverlay" xml:space="preserve">
@@ -1120,13 +1120,13 @@
<value>URL poslužitelja ikona</value>
</data>
<data name="AutofillWithBitwarden" xml:space="preserve">
<value>Auto-ispuni Bitwarden-om</value>
<value>Bitwarden auto-ispuna</value>
</data>
<data name="VaultIsLocked" xml:space="preserve">
<value>Trezor je zaključan</value>
</data>
<data name="GoToMyVault" xml:space="preserve">
<value>Idi na moj trezor</value>
<value>Uđi u moj trezor</value>
</data>
<data name="Collections" xml:space="preserve">
<value>Zbirke</value>
@@ -1355,7 +1355,7 @@
<value>Pretraživanje mape</value>
</data>
<data name="SearchType" xml:space="preserve">
<value>Tip pretrage</value>
<value>Pretraži ovu vrstu</value>
</data>
<data name="Type" xml:space="preserve">
<value>Vrsta</value>
@@ -1446,7 +1446,7 @@
<value>Postavi svoj PIN kôd za otključavanje Bitwardena. Postavke PIN-a se resetiraju ako se potpuno odjaviš iz aplikacije.</value>
</data>
<data name="LoggedInAsOn" xml:space="preserve">
<value>Prijavljen kao {0} na {1}.</value>
<value>Prijavljen/a kao {0} na {1}.</value>
<comment>ex: Logged in as user@example.com on bitwarden.com.</comment>
</data>
<data name="VaultLockedMasterPassword" xml:space="preserve">
@@ -1483,7 +1483,7 @@
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="ClearClipboardDescription" xml:space="preserve">
<value>Automatski očisti kopirane vrijednosti iz međuspremnika.</value>
<value>Vremenski period automatskog pražnjenja međuspremnika.</value>
<comment>Clipboard is the operating system thing where you copy/paste data to on your device.</comment>
</data>
<data name="DefaultUriMatchDetection" xml:space="preserve">
@@ -1491,14 +1491,14 @@
<comment>Default URI match detection for auto-fill.</comment>
</data>
<data name="DefaultUriMatchDetectionDescription" xml:space="preserve">
<value>Odaberi zadani način na koji će se riješavati otkrivanje URI-ja za prijavu pri izvođenju radnji kao što je auto-ispuna.</value>
<value>Biranje zadanog načina na koji će se riješavati otkrivanje URI-ja za prijavu pri izvođenju radnji kao što je auto-ispuna.</value>
</data>
<data name="Theme" xml:space="preserve">
<value>Tema</value>
<comment>Color theme</comment>
</data>
<data name="ThemeDescription" xml:space="preserve">
<value>Promijeni temu boja.</value>
<value>Mijenja boju aplikacije. </value>
</data>
<data name="RestartIsRequired" xml:space="preserve">
<value>Potrebno je ponovo pokretanje.</value>
@@ -1520,7 +1520,7 @@
<value>Obavezno otključavanje glavnom lozinkom pri ponovnom pokretanju aplikacije?</value>
</data>
<data name="Black" xml:space="preserve">
<value>Crno</value>
<value>Crna</value>
<comment>The color black</comment>
</data>
<data name="BlacklistedUris" xml:space="preserve">
@@ -1567,7 +1567,7 @@
<value>Biometrijska autentifikacija</value>
</data>
<data name="Biometrics" xml:space="preserve">
<value>Biometrija</value>
<value>biometrijom</value>
</data>
<data name="UseBiometricsToUnlock" xml:space="preserve">
<value>Koristi biometriju za otključavanje</value>
@@ -1603,10 +1603,10 @@
<value>Ovaj izvoz sadrži podatke trezora u nešifriranom obliku! Izvezenu datoteku se ne bi smjelo pohranjivati ili slati putem nesigurnih kanala (npr. e-poštom). Izbriši ju odmah nakon završetka korištenja.</value>
</data>
<data name="EncExportKeyWarning" xml:space="preserve">
<value>This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file.</value>
<value>Ovaj izvoz šifrira tvoje podatke koristeći ključ za šifriranje tvojeg računa. Ako ikada rotiraš ključ za šifriranje, potrebno je ponovno izvesti podatke, jer neće biti moguće dešifrirati ovu izvezenu datoteku.</value>
</data>
<data name="EncExportAccountWarning" xml:space="preserve">
<value>Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account.</value>
<value>Ključ za šifriranje jedinstven je za svakog Bitwarden korisnika, kako bi se šifrirani izvoz mogao uvesti u drugi korisnički račun.</value>
</data>
<data name="ExportVaultConfirmationTitle" xml:space="preserve">
<value>Potvrdi izvoz trezora</value>
@@ -1694,7 +1694,7 @@
<value>Uključi sinkronizaciju pri osvježavanju</value>
</data>
<data name="EnableSyncOnRefreshDescription" xml:space="preserve">
<value>Sinkroniziraj trezor povlačenja prema dolje.</value>
<value>Sinkronizacija trezora povlačenjem prema dolje.</value>
</data>
<data name="LogInSso" xml:space="preserve">
<value>Jedinstvena prijava na razini tvrtke (SSO)</value>
@@ -1806,169 +1806,197 @@
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AllSends" xml:space="preserve">
<value>All Sends</value>
<value>Svi Sendovi</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Sends" xml:space="preserve">
<value>Sends</value>
<value>Sendovi</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NameInfo" xml:space="preserve">
<value>A friendly name to describe this Send.</value>
<value>Nadimak za ovaj Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeText" xml:space="preserve">
<value>Text</value>
<value>Tekst</value>
</data>
<data name="TypeTextInfo" xml:space="preserve">
<value>The text you want to send.</value>
<value>Tekst kojeg želiš poslati</value>
</data>
<data name="HideTextByDefault" xml:space="preserve">
<value>When accessing the Send, hide the text by default</value>
<value>Zadano sakrij tekst pri pristupanju Sendu</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="TypeFile" xml:space="preserve">
<value>File</value>
<value>Datoteka</value>
</data>
<data name="TypeFileInfo" xml:space="preserve">
<value>The file you want to send.</value>
<value>Datoteka koju želiš poslati</value>
</data>
<data name="DeletionDate" xml:space="preserve">
<value>Deletion Date</value>
<value>Obriši za</value>
</data>
<data name="DeletionTime" xml:space="preserve">
<value>Deletion Time</value>
<value>Vrijeme brisanja</value>
</data>
<data name="DeletionDateInfo" xml:space="preserve">
<value>The Send will be permanently deleted on the specified date and time.</value>
<value>Send će nakon navedenog vremena biti trajno izbrisan.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PendingDelete" xml:space="preserve">
<value>Pending deletion</value>
<value>Čeka brisanje</value>
</data>
<data name="ExpirationDate" xml:space="preserve">
<value>Expiration Date</value>
<value>Vremenski ograničeni pristup</value>
</data>
<data name="ExpirationTime" xml:space="preserve">
<value>Expiration Time</value>
<value>Vrijeme isteka</value>
</data>
<data name="ExpirationDateInfo" xml:space="preserve">
<value>If set, access to this Send will expire on the specified date and time.</value>
<value>Pristup ovom Sendu neće biti moguć nakon navednog roka.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="Expired" xml:space="preserve">
<value>Expired</value>
<value>Isteklo</value>
</data>
<data name="MaximumAccessCount" xml:space="preserve">
<value>Maximum Access Count</value>
<value>Ograničeni broj pristupanja</value>
</data>
<data name="MaximumAccessCountInfo" xml:space="preserve">
<value>If set, users will no longer be able to access this send once the maximum access count is reached.</value>
<value>Ako je određen, ovom Sendu će se moći pristupiti samo ograničeni broj puta.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="MaximumAccessCountReached" xml:space="preserve">
<value>Max access count reached</value>
<value>Dostignut najveći broj pristupanja</value>
</data>
<data name="CurrentAccessCount" xml:space="preserve">
<value>Current Access Count</value>
<value>Trenutni broj pristupanja</value>
</data>
<data name="NewPassword" xml:space="preserve">
<value>New Password</value>
<value>Nova lozinka</value>
</data>
<data name="PasswordInfo" xml:space="preserve">
<value>Optionally require a password for users to access this Send.</value>
<value>Neobavezno zahtijevaj korisnika lozinku za pristup ovom Sendu.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="RemovePassword" xml:space="preserve">
<value>Remove Password</value>
<value>Ukloni lozinku</value>
</data>
<data name="AreYouSureRemoveSendPassword" xml:space="preserve">
<value>Are you sure you want to remove the password?</value>
<value>Sigurno želiš ukloniti lozinku?</value>
</data>
<data name="RemovingSendPassword" xml:space="preserve">
<value>Removing password</value>
<value>Lozinka uklonjena</value>
</data>
<data name="SendPasswordRemoved" xml:space="preserve">
<value>Password has been removed.</value>
<value>Lozinka uklonjena.</value>
</data>
<data name="NotesInfo" xml:space="preserve">
<value>Private notes about this Send.</value>
<value>Privatne bilješke o Sendu.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="DisableSend" xml:space="preserve">
<value>Disable this Send so that no one can access it.</value>
<value>Onemogući ovaj Send da mu nitko ne može pristupiti.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NoSends" xml:space="preserve">
<value>There are no sends in your account.</value>
<value>Nema Sendova na tvojem računu.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddASend" xml:space="preserve">
<value>Add a Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="CopyLink" xml:space="preserve">
<value>Copy Link</value>
<value>Kopiraj vezu</value>
</data>
<data name="ShareLink" xml:space="preserve">
<value>Share Link</value>
<value>Dijeli vezu</value>
</data>
<data name="SendLink" xml:space="preserve">
<value>Send link</value>
<value>Veza na Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SearchSends" xml:space="preserve">
<value>Search Sends</value>
<value>Pretraži Sendove</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="EditSend" xml:space="preserve">
<value>Edit Send</value>
<value>Uredi Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AddSend" xml:space="preserve">
<value>Add Send</value>
<value>Dodaj Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AreYouSureDeleteSend" xml:space="preserve">
<value>Are you sure you want to delete this Send?</value>
<value>Sigurno želiš izbrisati ovaj Send?</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDeleted" xml:space="preserve">
<value>Send has been deleted.</value>
<value>Send izbrisan.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendUpdated" xml:space="preserve">
<value>Send updated.</value>
<value>Send ažuriran.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="NewSendCreated" xml:space="preserve">
<value>New send created.</value>
<value>Stvoren novi Send</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="OneDay" xml:space="preserve">
<value>1 day</value>
<value>1 dan</value>
</data>
<data name="TwoDays" xml:space="preserve">
<value>2 days</value>
<value>2 dana</value>
</data>
<data name="ThreeDays" xml:space="preserve">
<value>3 days</value>
<value>3 dana</value>
</data>
<data name="SevenDays" xml:space="preserve">
<value>7 days</value>
<value>7 dana</value>
</data>
<data name="ThirtyDays" xml:space="preserve">
<value>30 days</value>
<value>30 dana</value>
</data>
<data name="Custom" xml:space="preserve">
<value>Custom</value>
<value>Prilagođeno</value>
</data>
<data name="ShareOnSave" xml:space="preserve">
<value>Share this Send upon save.</value>
<value>Dijeli Send nakon spremanja</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendDisabledWarning" xml:space="preserve">
<value>Due to an enterprise policy, you are only able to delete an existing Send.</value>
<value>Pravila tvrtke omogućuju brisanje samo postojećeg Senda</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="AboutSend" xml:space="preserve">
<value>About Send</value>
<value>O Sendu</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="HideEmail" xml:space="preserve">
<value>Sakrij moju adresu e-pošte od primatelja.</value>
</data>
<data name="SendOptionsPolicyInEffect" xml:space="preserve">
<value>Jedno ili više pravila organizacije utječe na postavke Senda.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFilePremiumRequired" xml:space="preserve">
<value>Kod besplatnog računa moguće je dijeljenje samo teksta. Za slanje datoteka potrebno je Premium članstvo.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="SendFileEmailVerificationRequired" xml:space="preserve">
<value>Moraš ovjeriti svoju e-poštu za koritšenje datoteka sa Sendom.</value>
<comment>'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated.</comment>
</data>
<data name="PasswordPrompt" xml:space="preserve">
<value>Master password re-prompt</value>
</data>
<data name="PasswordConfirmation" xml:space="preserve">
<value>Master password confirmation</value>
</data>
<data name="PasswordConfirmationDesc" xml:space="preserve">
<value>This action is protected, to continue please re-enter your master password to verify your identity.</value>
</data>
</root>

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