Compare commits

...

83 Commits

Author SHA1 Message Date
Kyle Spearrin
5501ab9083 bump build 2017-09-29 17:42:11 -04:00
Kyle Spearrin
660a21deb1 info.plist updates 2017-09-29 17:22:52 -04:00
Kyle Spearrin
be7949b909 remove old icons 2017-09-29 17:15:16 -04:00
Kyle Spearrin
a688656f6d asset catalog with app icons 2017-09-29 17:14:52 -04:00
Kyle Spearrin
62365529cc Revert "asset catalog with app icon for itunes"
This reverts commit dcea869098.
2017-09-29 17:10:12 -04:00
Kyle Spearrin
dcea869098 asset catalog with app icon for itunes 2017-09-29 16:29:29 -04:00
Kyle Spearrin
634a8702cd autofill adjustments 2017-09-29 15:12:33 -04:00
Kyle Spearrin
fee993c309 new review link for ios 11 2017-09-28 23:26:59 -04:00
Kyle Spearrin
bf76707e92 shorthand null check 2017-09-28 22:56:36 -04:00
Kyle Spearrin
da847f6567 ios extension autofill fixes 2017-09-28 22:54:46 -04:00
Kyle Spearrin
7a5d25f2e3 version bump 2017-09-28 16:54:51 -04:00
Kyle Spearrin
bf0dedd447 new languages 2017-09-27 23:26:03 -04:00
Kyle Spearrin
3f7dcc6acf New Crowdin translations (#138)
* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Danish)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Vietnamese)

* New translations copy.resx (Vietnamese)

* New translations AppResources.resx (Vietnamese)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Thai)

* New translations AppResources.resx (Turkish)

* New translations AppResources.resx (Dutch)

* New translations AppResources.resx (Finnish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Indonesian)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Chinese Simplified)
2017-09-27 23:17:34 -04:00
Kyle Spearrin
2efe8b4186 switch back to bearer 2017-09-27 23:06:41 -04:00
Kyle Spearrin
068f5771b2 make notes editor taller 2017-09-27 14:36:55 -04:00
Kyle Spearrin
c2b1be288e remove MovementMethod to enable highlight 2017-09-27 14:36:42 -04:00
Kyle Spearrin
163ad248af autofill custom fields for iOS extension 2017-09-26 14:38:12 -04:00
Kyle Spearrin
4598c3d852 resources for test project 2017-09-26 12:42:50 -04:00
Kyle Spearrin
a1dec131c7 dont automatically use latest target framework 2017-09-26 12:20:20 -04:00
Kyle Spearrin
133585f46a revert to 7.1 2017-09-26 11:57:49 -04:00
Kyle Spearrin
3ea81ce2fb reveal hidden value for custom fields 2017-09-26 11:06:50 -04:00
Kyle Spearrin
590fe211c4 edit custom fields 2017-09-25 17:13:20 -04:00
Kyle Spearrin
78cda03d61 cleanup login view of custom fields. 2017-09-25 15:05:36 -04:00
Kyle Spearrin
e126cbf644 sync and display custom fields for login 2017-09-22 17:32:20 -04:00
Kyle Spearrin
cc12ae7712 sub-classed login props for cipher req 2017-09-21 10:50:15 -04:00
Kyle Spearrin
e8486abccf change login to cipher apis 2017-09-20 17:37:09 -04:00
Kyle Spearrin
15f074a45b remove duplicate / from API routes 2017-09-20 13:23:47 -04:00
Kyle Spearrin
a426d98e92 change syncing to use new sync api 2017-09-20 13:17:05 -04:00
Kyle Spearrin
45d171e0e3 notes keyboard type is "Text" for auto-cap 2017-09-19 16:34:29 -04:00
Kyle Spearrin
5950c33a43 qs tile to quickly launch my vault (android) 2017-09-19 15:55:15 -04:00
Kyle Spearrin
ea1b584436 fixes for mobile app uris 2017-09-15 08:12:24 -04:00
Kyle Spearrin
a24ede364d switch all monospaced fonts on iOS to menlo 2017-09-14 15:17:28 -04:00
Kyle Spearrin
c6fe456cac more terms to ignore from package names 2017-09-12 17:18:59 -04:00
Kyle Spearrin
4008fb3a53 search packagename terms on android autofill 2017-09-12 17:01:13 -04:00
Kyle Spearrin
96588089ef filter out "launcher" apps from autofill service 2017-09-12 15:54:08 -04:00
Kyle Spearrin
e4c96dc6d8 all editor to be scrollable 2017-09-12 15:41:18 -04:00
Kyle Spearrin
c205e0da1b add icon to hockeyapp activity modification 2017-09-12 14:57:19 -04:00
Kyle Spearrin
7b61605834 version bump 2017-09-12 10:13:00 -04:00
Kyle Spearrin
e7fb05d7e0 update info.plist language resource array 2017-09-12 10:11:30 -04:00
Kyle Spearrin
8f0680f5fc new language resource files 2017-09-12 10:08:32 -04:00
Kyle Spearrin
9c03dd001c New Crowdin translations (#129)
* New translations AppResources.resx (Romanian)

* New translations AppResources.resx (Russian)

* New translations AppResources.resx (Slovak)

* New translations AppResources.resx (Polish)

* New translations AppResources.resx (Portuguese)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations copy.resx (Turkish)

* New translations AppResources.resx (Turkish)

* New translations copy.resx (Turkish)

* New translations copy.resx (Turkish)

* New translations copy.resx (Ukrainian)

* New translations copy.resx (Ukrainian)

* New translations copy.resx (Ukrainian)

* New translations AppResources.resx (Ukrainian)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Spanish)

* New translations AppResources.resx (Swedish)

* New translations AppResources.resx (Czech)

* New translations AppResources.resx (Dutch)

* New translations copy.resx (Dutch)

* New translations AppResources.resx (Finnish)

* New translations copy.resx (Dutch)

* New translations copy.resx (Dutch)

* New translations AppResources.resx (Chinese Traditional)

* New translations AppResources.resx (Croatian)

* New translations AppResources.resx (Indonesian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Hungarian)

* New translations copy.resx (Hungarian)

* New translations AppResources.resx (French)

* New translations AppResources.resx (Hindi)

* New translations AppResources.resx (Hungarian)

* New translations AppResources.resx (Chinese Simplified)
2017-09-12 09:09:00 -04:00
Kyle Spearrin
30407f5b4e handle iOS apps that don't specify a url properly 2017-09-09 13:41:10 -04:00
Kyle Spearrin
3a5378d201 do not attempt autofill on android 4.4 2017-09-08 09:16:21 -04:00
Kyle Spearrin
d4f3577f5e use latest VS image 2017-09-07 00:34:51 -04:00
Kyle Spearrin
408e9bf3fc conditionals if device has camera or not 2017-09-07 00:33:19 -04:00
Kyle Spearrin
f5dd91afe5 parse IP addresses as base domains 2017-09-06 23:08:24 -04:00
Kyle Spearrin
8922459418 mark hockeyapp UpdateActivity as exported=false 2017-09-04 23:34:30 -04:00
Kyle Spearrin
caeadbc41e version bump for ios 2017-08-31 21:13:25 -04:00
Kyle Spearrin
99143c0e3b Update appveyor.yml 2017-08-31 08:17:55 -04:00
Kyle Spearrin
1b145e38a3 version bump 2017-08-30 22:43:19 -04:00
Kyle Spearrin
f59cce15c0 move delay after 2017-08-30 22:21:56 -04:00
Kyle Spearrin
7655c251a2 re-try focus on password lock page 2017-08-30 22:19:14 -04:00
Kyle Spearrin
5608cb542f update pinvoke libs 2017-08-30 22:15:30 -04:00
Kyle Spearrin
62add53c08 clear org key cache 2017-08-30 22:15:10 -04:00
Kyle Spearrin
43bae6c05b use bearer3 still for now 2017-08-30 14:23:07 -04:00
Kyle Spearrin
55777d33ad pl language 2017-08-30 10:14:20 -04:00
Kyle Spearrin
0f5d14b589 New Crowdin translations (#124)
* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Romanian)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Russian)

* New translations copy.resx (Romanian)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Polish)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Japanese)

* New translations copy.resx (Polish)

* New translations copy.resx (Polish)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Portuguese)

* New translations AppResources.resx (Portuguese)

* New translations copy.resx (Russian)

* New translations copy.resx (Russian)

* New translations copy.resx (Swedish)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Swedish)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Thai)

* New translations copy.resx (Thai)

* New translations copy.resx (Thai)

* New translations copy.resx (Spanish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Slovak)

* New translations AppResources.resx (Slovak)

* New translations copy.resx (Russian)

* New translations copy.resx (Slovak)

* New translations copy.resx (Slovak)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Spanish)

* New translations copy.resx (Japanese)

* New translations copy.resx (Japanese)

* New translations AppResources.resx (Czech)

* New translations copy.resx (Croatian)

* New translations copy.resx (Croatian)

* New translations copy.resx (Czech)

* New translations copy.resx (Czech)

* New translations copy.resx (Finnish)

* New translations AppResources.resx (Finnish)

* New translations copy.resx (Czech)

* New translations copy.resx (Croatian)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Chinese Simplified)

* New translations AppResources.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Finnish)

* New translations copy.resx (Finnish)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Indonesian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Italian)

* New translations copy.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations copy.resx (Hindi)

* New translations copy.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (Hindi)

* New translations copy.resx (Hindi)

* New translations AppResources.resx (Chinese Simplified)
2017-08-30 08:53:59 -04:00
Kyle Spearrin
00703d1570 setting with custom defaultsName 2017-08-29 16:58:02 -04:00
Kyle Spearrin
fd03c33f4d update xam forms lib 2017-08-29 16:21:32 -04:00
Kyle Spearrin
c20f91b6d8 update libs 2017-08-29 16:11:12 -04:00
Kyle Spearrin
10b22e9e42 update and refactor for settings changes 2017-08-29 16:03:26 -04:00
Kyle Spearrin
329f0871d5 cleanup and update sqlite packages 2017-08-29 15:38:22 -04:00
Kyle Spearrin
66996f491c retry focus until it works on pin lock page 2017-08-29 15:25:16 -04:00
Kyle Spearrin
9ae39f3900 visible w/ no suggestions for password entries 2017-08-29 15:05:56 -04:00
Kyle Spearrin
9d0db3c1e5 remove setting soft input mode 2017-08-29 14:33:25 -04:00
Kyle Spearrin
5932dd99ad remove to web vault url 2017-08-28 18:08:26 -04:00
Kyle Spearrin
910f0083cd allow setting vault url for environment 2017-08-28 17:50:17 -04:00
Kyle Spearrin
32a8676572 wrap username and password at full font size 2017-08-28 17:46:28 -04:00
Kyle Spearrin
801829ccbf update packages for nsub in test 2017-08-23 11:54:18 -04:00
Kyle Spearrin
b5107d21dd set custom environment urls from home page 2017-08-23 11:40:40 -04:00
Kyle Spearrin
158bf873bd return from autofill events when device is asleep 2017-08-15 12:28:48 -04:00
Kyle Spearrin
40cfb9876d properly background unregister call 2017-08-11 14:24:44 -04:00
Kyle Spearrin
12e3214f70 handle non-root URLs 2017-08-11 14:24:32 -04:00
Kyle Spearrin
0eb68ec461 revert old bearer code. use bearer scheme again 2017-08-10 10:16:58 -04:00
Kyle Spearrin
f231565163 delay credential clear when no passwords 2017-08-09 21:40:59 -04:00
Kyle Spearrin
7cca53bcc5 vault is default page when searching from autofill 2017-08-01 22:11:00 -04:00
Kyle Spearrin
be94c94309 comment out test code 2017-07-31 12:34:19 -04:00
Kyle Spearrin
8e2d654b40 fix url if malformed 2017-07-31 12:30:05 -04:00
Kyle Spearrin
2ed5c0c5cc add lightning & focus browser support for autofill 2017-07-31 11:30:07 -04:00
Kyle Spearrin
745ad3b9e9 better null checks for tokens 2017-07-31 10:23:52 -04:00
Kyle Spearrin
3ce114760f New Crowdin translations (#111)
* New translations copy.resx (Romanian)

* New translations copy.resx (Romanian)

* New translations copy.resx (Romanian)

* New translations AppResources.resx (Russian)

* New translations copy.resx (Russian)

* New translations AppResources.resx (Slovak)

* New translations copy.resx (Russian)

* New translations copy.resx (Russian)

* New translations AppResources.resx (Romanian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese)

* New translations AppResources.resx (Portuguese)

* New translations copy.resx (Japanese)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Portuguese)

* New translations copy.resx (Portuguese, Brazilian)

* New translations copy.resx (Portuguese, Brazilian)

* New translations AppResources.resx (Portuguese, Brazilian)

* New translations copy.resx (Slovak)

* New translations copy.resx (Slovak)

* New translations copy.resx (Thai)

* New translations copy.resx (Thai)

* New translations AppResources.resx (Thai)

* New translations copy.resx (Thai)

* New translations AppResources.resx (Polish)

* New translations copy.resx (Polish)

* New translations copy.resx (Polish)

* New translations copy.resx (Polish)

* New translations copy.resx (Swedish)

* New translations copy.resx (Swedish)

* New translations copy.resx (Spanish)

* New translations AppResources.resx (Spanish)

* New translations copy.resx (Slovak)

* New translations copy.resx (Spanish)

* New translations copy.resx (Spanish)

* New translations copy.resx (Swedish)

* New translations AppResources.resx (Swedish)

* New translations copy.resx (Japanese)

* New translations copy.resx (Japanese)

* New translations AppResources.resx (Czech)

* New translations copy.resx (Croatian)

* New translations copy.resx (Croatian)

* New translations copy.resx (Czech)

* New translations copy.resx (Czech)

* New translations copy.resx (Finnish)

* New translations AppResources.resx (Finnish)

* New translations copy.resx (Czech)

* New translations copy.resx (Croatian)

* New translations AppResources.resx (Croatian)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Chinese Simplified)

* New translations copy.resx (Chinese Simplified)

* New translations AppResources.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Chinese Traditional)

* New translations copy.resx (Finnish)

* New translations copy.resx (Finnish)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Indonesian)

* New translations copy.resx (Indonesian)

* New translations AppResources.resx (Italian)

* New translations copy.resx (Italian)

* New translations AppResources.resx (Japanese)

* New translations copy.resx (Italian)

* New translations copy.resx (Italian)

* New translations AppResources.resx (Indonesian)

* New translations copy.resx (Hindi)

* New translations copy.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (French)

* New translations copy.resx (French)

* New translations AppResources.resx (Hindi)

* New translations copy.resx (Hindi)

* New translations copy.resx (Hindi)

* New translations AppResources.resx (Chinese Simplified)
2017-07-31 10:05:43 -04:00
Kyle Spearrin
bae7d1fc1d version bump for android 2017-07-28 17:27:24 -04:00
Kyle Spearrin
e4d9dfc128 added broadcast receiver for when android updated 2017-07-28 17:21:39 -04:00
267 changed files with 15722 additions and 2612 deletions

View File

@@ -16,7 +16,7 @@
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v7.1</TargetFrameworkVersion>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
@@ -103,13 +103,13 @@
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\MonoAndroid10\FFImageLoading.Platform.dll</HintPath>
</Reference>
<Reference Include="FormsViewGroup, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
</Reference>
<Reference Include="HockeySDK, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.2\lib\MonoAndroid403\HockeySDK.dll</HintPath>
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.5\lib\MonoAndroid403\HockeySDK.dll</HintPath>
</Reference>
<Reference Include="HockeySDK.AndroidBindings, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.2\lib\MonoAndroid403\HockeySDK.AndroidBindings.dll</HintPath>
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.5\lib\MonoAndroid403\HockeySDK.AndroidBindings.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
@@ -126,46 +126,42 @@
<HintPath>..\..\packages\PCLCrypto.2.0.147\lib\MonoAndroid23\PCLCrypto.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PInvoke.BCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.BCrypt.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.BCrypt, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.BCrypt.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.BCrypt.dll</HintPath>
</Reference>
<Reference Include="PInvoke.Kernel32, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Kernel32.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.Kernel32, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Kernel32.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.Kernel32.dll</HintPath>
</Reference>
<Reference Include="PInvoke.NCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.NCrypt.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.NCrypt, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.NCrypt.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.NCrypt.dll</HintPath>
</Reference>
<Reference Include="PInvoke.Windows.Core, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Windows.Core.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.Windows.Core, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Windows.Core.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.Windows.Core.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
<Reference Include="Plugin.Connectivity, Version=3.0.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.3.0.2\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
<Reference Include="Plugin.Connectivity.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.3.0.2\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.CurrentActivity, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Fingerprint, Version=1.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.4\lib\MonoAndroid\Plugin.Fingerprint.dll</HintPath>
<Reference Include="Plugin.Fingerprint, Version=1.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.5\lib\MonoAndroid\Plugin.Fingerprint.dll</HintPath>
</Reference>
<Reference Include="Plugin.Fingerprint.Abstractions, Version=1.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.4\lib\MonoAndroid\Plugin.Fingerprint.Abstractions.dll</HintPath>
<Reference Include="Plugin.Fingerprint.Abstractions, Version=1.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.5\lib\MonoAndroid\Plugin.Fingerprint.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Fingerprint.Android.Samsung, Version=1.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.4\lib\MonoAndroid\Plugin.Fingerprint.Android.Samsung.dll</HintPath>
<Reference Include="Plugin.Fingerprint.Android.Samsung, Version=1.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.5\lib\MonoAndroid\Plugin.Fingerprint.Android.Samsung.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
<Reference Include="Plugin.Settings, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.dll</HintPath>
@@ -175,48 +171,30 @@
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\MonoAndroid10\PushNotification.Plugin.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SimpleInjector, Version=4.0.7.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimpleInjector.4.0.7\lib\netstandard1.3\SimpleInjector.dll</HintPath>
<Reference Include="SimpleInjector, Version=4.0.8.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<HintPath>..\..\packages\SimpleInjector.4.0.8\lib\netstandard1.3\SimpleInjector.dll</HintPath>
</Reference>
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.2.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCL.batteries, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCL.bundle_green.0.9.3\lib\MonoAndroid\SQLitePCL.batteries.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCL.raw, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCL.raw.0.9.3\lib\MonoAndroid\SQLitePCL.raw.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLPlugin_esqlite3, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCL.plugin.sqlite3.android.0.9.3\lib\MonoAndroid\SQLitePCLPlugin_esqlite3.dll</HintPath>
<Private>True</Private>
<Reference Include="SQLite-net, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.4.118\lib\netstandard1.1\SQLite-net.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\MonoAndroid\SQLitePCLRaw.batteries_green.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\MonoAndroid\SQLitePCLRaw.batteries_green.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\MonoAndroid\SQLitePCLRaw.batteries_v2.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\MonoAndroid\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.2\lib\MonoAndroid\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.8\lib\MonoAndroid\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.lib.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e4ad490600e2234c, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.lib.e_sqlite3.android.1.1.2\lib\MonoAndroid\SQLitePCLRaw.lib.e_sqlite3.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.lib.e_sqlite3.android.1.1.8\lib\MonoAndroid\SQLitePCLRaw.lib.e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.provider.e_sqlite3.android.1.1.2\lib\MonoAndroid\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.provider.e_sqlite3.android.1.1.8\lib\MonoAndroid\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -259,16 +237,16 @@
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform.Android, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Analytics, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Analytics.29.0.0.2\lib\MonoAndroid41\Xamarin.GooglePlayServices.Analytics.dll</HintPath>
@@ -330,6 +308,7 @@
<Compile Include="Controls\ExtendedTextCellRenderer.cs" />
<Compile Include="Controls\ExtendedPickerRenderer.cs" />
<Compile Include="Controls\ExtendedEntryRenderer.cs" />
<Compile Include="MyVaultTileService.cs" />
<Compile Include="Services\HttpService.cs" />
<Compile Include="Services\AndroidKeyStoreStorageService.cs" />
<Compile Include="Services\LocalizeService.cs" />
@@ -348,6 +327,7 @@
<Compile Include="Services\ReflectionService.cs" />
<Compile Include="Services\SqlService.cs" />
<Compile Include="SplashActivity.cs" />
<Compile Include="PackageReplacedReceiver.cs" />
<Compile Include="Utilities.cs" />
</ItemGroup>
<ItemGroup>
@@ -950,6 +930,24 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\trash.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\cog.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-hdpi\cog.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xhdpi\cog.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxhdpi\cog.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable-xxxhdpi\cog.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\shield.png" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
@@ -958,10 +956,10 @@
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
</Target>
<Import Project="..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets" Condition="Exists('..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.2\build\Xamarin.GooglePlayServices.Basement.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@@ -11,7 +11,7 @@ using XLabs.Ioc;
namespace Bit.Android
{
[Service(Permission = "android.permission.BIND_ACCESSIBILITY_SERVICE", Label = "bitwarden")]
[Service(Permission = global::Android.Manifest.Permission.BindAccessibilityService, Label = "bitwarden")]
[IntentFilter(new string[] { "android.accessibilityservice.AccessibilityService" })]
[MetaData("android.accessibilityservice", Resource = "@xml/accessibilityservice")]
public class AutofillService : AccessibilityService
@@ -42,6 +42,7 @@ namespace Bit.Android
(s) => s.Split(' ').FirstOrDefault()),
new Browser("org.mozilla.firefox", "url_bar_title"),
new Browser("org.mozilla.firefox_beta", "url_bar_title"),
new Browser("org.mozilla.focus", "display_url"),
new Browser("com.ghostery.android.ghostery", "search_field"),
new Browser("org.adblockplus.browser", "url_bar_title"),
new Browser("com.htc.sense.browser", "title"),
@@ -52,7 +53,9 @@ namespace Bit.Android
new Browser("com.mx.browser", "address_editor_with_progress"),
new Browser("com.mx.browser.tablet", "address_editor_with_progress"),
new Browser("com.linkbubble.playstore", "url_text"),
new Browser("com.ksmobile.cb", "address_bar_edit_text")
new Browser("com.ksmobile.cb", "address_bar_edit_text"),
new Browser("acr.browser.lightning", "search"),
new Browser("acr.browser.barebones", "search")
}.ToDictionary(n => n.PackageName);
private readonly IAppSettingsService _appSettings;
@@ -66,11 +69,22 @@ namespace Bit.Android
public override void OnAccessibilityEvent(AccessibilityEvent e)
{
var powerManager = (PowerManager)GetSystemService(PowerService);
if(Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch && !powerManager.IsInteractive)
{
return;
}
else if(Build.VERSION.SdkInt < BuildVersionCodes.Lollipop && !powerManager.IsScreenOn)
{
return;
}
try
{
var root = RootInActiveWindow;
if(e == null || root == null || string.IsNullOrWhiteSpace(e.PackageName) ||
e.PackageName == SystemUiPackage || root.PackageName != e.PackageName)
e.PackageName == SystemUiPackage || e.PackageName.Contains("launcher") ||
root.PackageName != e.PackageName)
{
return;
}
@@ -216,9 +230,18 @@ namespace Bit.Android
cancelNotification = false;
}
}
AutofillActivity.LastCredentials = null;
}
else if(AutofillActivity.LastCredentials != null)
{
System.Threading.Tasks.Task.Run(async () =>
{
await System.Threading.Tasks.Task.Delay(1000);
AutofillActivity.LastCredentials = null;
});
}
AutofillActivity.LastCredentials = null;
passwordNodes.Dispose();
return cancelNotification;
}
@@ -319,11 +342,15 @@ namespace Bit.Android
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
var notificationContent = Build.VERSION.SdkInt > BuildVersionCodes.KitkatWatch ?
App.Resources.AppResources.BitwardenAutofillServiceNotificationContent :
App.Resources.AppResources.BitwardenAutofillServiceNotificationContentOld;
var builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.notification_sm)
.SetContentTitle(App.Resources.AppResources.BitwardenAutofillService)
.SetContentText(App.Resources.AppResources.BitwardenAutofillServiceNotificationContent)
.SetTicker(App.Resources.AppResources.BitwardenAutofillServiceNotificationContent)
.SetContentText(notificationContent)
.SetTicker(notificationContent)
.SetWhen(now)
.SetContentIntent(pendingIntent);

View File

@@ -4,6 +4,8 @@ using Bit.Android.Controls;
using Bit.App.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Android.Text.Method;
using Android.Views;
[assembly: ExportRenderer(typeof(ExtendedEditor), typeof(ExtendedEditorRenderer))]
namespace Bit.Android.Controls
@@ -17,6 +19,7 @@ namespace Bit.Android.Controls
var view = (ExtendedEditor)Element;
SetBorder(view);
SetScrollable();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -44,5 +47,35 @@ namespace Bit.Android.Controls
Control.SetBackgroundColor(global::Android.Graphics.Color.Transparent);
}
}
private void SetScrollable()
{
// While scrolling inside Editor stop scrolling parent view.
Control.OverScrollMode = OverScrollMode.Always;
Control.ScrollBarStyle = ScrollbarStyles.InsideInset;
Control.SetOnTouchListener(new EditorTouchListener());
// For Scrolling in Editor innner area
Control.VerticalScrollBarEnabled = true;
Control.ScrollBarStyle = ScrollbarStyles.InsideInset;
// Force scrollbars to be displayed
var arr = Control.Context.Theme.ObtainStyledAttributes(new int[0]);
InitializeScrollbars(arr);
arr.Recycle();
}
public class EditorTouchListener : Java.Lang.Object, IOnTouchListener
{
public bool OnTouch(global::Android.Views.View v, MotionEvent e)
{
v.Parent?.RequestDisallowInterceptTouchEvent(true);
if((e.Action & MotionEventActions.Up) != 0 && (e.ActionMasked & MotionEventActions.Up) != 0)
{
v.Parent?.RequestDisallowInterceptTouchEvent(false);
}
return false;
}
}
}
}

View File

@@ -55,6 +55,11 @@ namespace Bit.Android.Controls
Control.SetRawInputType(Control.InputType |= InputTypes.TextFlagNoSuggestions);
}
if(_view.IsPassword)
{
Control.SetRawInputType(InputTypes.TextFlagNoSuggestions | InputTypes.TextVariationVisiblePassword);
}
_view.ToggleIsPassword += ToggleIsPassword;
if(_view.FontFamily == "monospace")
@@ -69,6 +74,7 @@ namespace Bit.Android.Controls
var cursorEnd = Control.SelectionEnd;
Control.TransformationMethod = _isPassword ? null : new PasswordTransformationMethod();
Control.SetRawInputType(InputTypes.TextFlagNoSuggestions | InputTypes.TextVariationVisiblePassword);
// set focus
Control.RequestFocus();
@@ -85,11 +91,9 @@ namespace Bit.Android.Controls
}
// show keyboard
var app = XLabs.Ioc.Resolver.Resolve<global::Android.App.Application>();
var inputMethodManager =
app.GetSystemService(global::Android.Content.Context.InputMethodService) as InputMethodManager;
inputMethodManager.ShowSoftInput(Control, ShowFlags.Forced);
inputMethodManager.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
var imm = Forms.Context.GetSystemService(global::Android.Content.Context.InputMethodService) as InputMethodManager;
imm.ShowSoftInput(Control, ShowFlags.Forced);
imm.ToggleSoftInput(ShowFlags.Forced, HideSoftInputFlags.ImplicitOnly);
_isPassword = _view.IsPasswordFromToggled = !_isPassword;
_toggledPassword = true;

View File

@@ -24,8 +24,7 @@ namespace Bit.Android
{
[Activity(Label = "bitwarden",
Icon = "@drawable/icon",
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
WindowSoftInputMode = SoftInput.StateHidden)]
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : FormsAppCompatActivity
{
private const string HockeyAppId = "d3834185b4a643479047b86c65293d42";
@@ -55,7 +54,6 @@ namespace Bit.Android
Task.Delay(10).Wait();
Console.WriteLine("A OnCreate");
Window.SetSoftInputMode(SoftInput.StateHidden);
if(!App.Utilities.Helpers.InDebugMode())
{
Window.AddFlags(WindowManagerFlags.Secure);
@@ -76,6 +74,7 @@ namespace Bit.Android
_settings = Resolver.Resolve<ISettings>();
LoadApplication(new App.App(
uri,
Intent.GetBooleanExtra("myVaultTile", false),
Resolver.Resolve<IAuthService>(),
Resolver.Resolve<IConnectivity>(),
Resolver.Resolve<IUserDialogs>(),

View File

@@ -220,7 +220,6 @@ namespace Bit.Android
container.RegisterSingleton<IFolderApiRepository, FolderApiRepository>();
container.RegisterSingleton<ILoginRepository, LoginRepository>();
container.RegisterSingleton<IAttachmentRepository, AttachmentRepository>();
container.RegisterSingleton<ILoginApiRepository, LoginApiRepository>();
container.RegisterSingleton<IConnectApiRepository, ConnectApiRepository>();
container.RegisterSingleton<IDeviceApiRepository, DeviceApiRepository>();
container.RegisterSingleton<IAccountsApiRepository, AccountsApiRepository>();
@@ -228,6 +227,7 @@ namespace Bit.Android
container.RegisterSingleton<ISettingsRepository, SettingsRepository>();
container.RegisterSingleton<ISettingsApiRepository, SettingsApiRepository>();
container.RegisterSingleton<ITwoFactorApiRepository, TwoFactorApiRepository>();
container.RegisterSingleton<ISyncApiRepository, SyncApiRepository>();
// Other
container.RegisterSingleton(CrossSettings.Current);

View File

@@ -0,0 +1,58 @@
using Android.App;
using Android.Content;
using Android.Service.QuickSettings;
using Java.Lang;
namespace Bit.Android
{
[Service(Permission = global::Android.Manifest.Permission.BindQuickSettingsTile,
Label = "@string/MyVault", Icon = "@drawable/shield")]
[IntentFilter(new string[] { ActionQsTile })]
public class MyVaultTileService : TileService
{
public override void OnTileAdded()
{
base.OnTileAdded();
}
public override void OnStartListening()
{
base.OnStartListening();
}
public override void OnStopListening()
{
base.OnStopListening();
}
public override void OnTileRemoved()
{
base.OnTileRemoved();
}
public override void OnClick()
{
base.OnClick();
if(IsLocked)
{
UnlockAndRun(new Runnable(() =>
{
LaunchMyVault();
}));
}
else
{
LaunchMyVault();
}
}
private void LaunchMyVault()
{
var intent = new Intent(this, typeof(SplashActivity));
intent.SetFlags(ActivityFlags.NewTask | ActivityFlags.SingleTop | ActivityFlags.ClearTop);
intent.PutExtra("myVaultTile", true);
StartActivityAndCollapse(intent);
}
}
}

View File

@@ -0,0 +1,22 @@
using Android.App;
using Android.Content;
using Bit.App.Abstractions;
using Bit.App.Utilities;
using Plugin.Settings.Abstractions;
using System.Diagnostics;
using XLabs.Ioc;
namespace Bit.Android
{
[BroadcastReceiver(Name = "com.x8bit.bitwarden.PackageReplacedReceiver", Exported = true)]
[IntentFilter(new[] { Intent.ActionMyPackageReplaced })]
public class PackageReplacedReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Debug.WriteLine("App updated!");
Helpers.PerformUpdateTasks(Resolver.Resolve<ISettings>(), Resolver.Resolve<IAppInfoService>(),
Resolver.Resolve<IDatabaseService>());
}
}
}

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.8.0" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.x8bit.bitwarden" android:versionName="1.11.0" android:installLocation="auto" android:versionCode="502" xmlns:tools="http://schemas.android.com/tools">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23" />
<uses-permission android:name="android.permission.INTERNET" />
@@ -13,6 +13,9 @@
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.x8bit.bitwarden.permission.C2D_MESSAGE" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<application android:label="bitwarden" android:theme="@style/BitwardenTheme" android:allowBackup="false">
<provider
android:name="android.support.v4.content.FileProvider"
@@ -23,5 +26,7 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
<activity android:name="net.hockeyapp.android.UpdateActivity" android:exported="false" android:icon="@drawable/icon" />
</application>
</manifest>

View File

@@ -127,10 +127,14 @@ namespace Bit.Android
global::HockeyApp.Resource.String.hockeyapp_expiry_info_title = global::Bit.Android.Resource.String.hockeyapp_expiry_info_title;
global::HockeyApp.Resource.String.hockeyapp_feedback_attach_file = global::Bit.Android.Resource.String.hockeyapp_feedback_attach_file;
global::HockeyApp.Resource.String.hockeyapp_feedback_attach_picture = global::Bit.Android.Resource.String.hockeyapp_feedback_attach_picture;
global::HockeyApp.Resource.String.hockeyapp_feedback_attachment_added = global::Bit.Android.Resource.String.hockeyapp_feedback_attachment_added;
global::HockeyApp.Resource.String.hockeyapp_feedback_attachment_button_text = global::Bit.Android.Resource.String.hockeyapp_feedback_attachment_button_text;
global::HockeyApp.Resource.String.hockeyapp_feedback_attachment_error = global::Bit.Android.Resource.String.hockeyapp_feedback_attachment_error;
global::HockeyApp.Resource.String.hockeyapp_feedback_attachment_loading = global::Bit.Android.Resource.String.hockeyapp_feedback_attachment_loading;
global::HockeyApp.Resource.String.hockeyapp_feedback_attachment_remove_description = global::Bit.Android.Resource.String.hockeyapp_feedback_attachment_remove_description;
global::HockeyApp.Resource.String.hockeyapp_feedback_attachment_removed = global::Bit.Android.Resource.String.hockeyapp_feedback_attachment_removed;
global::HockeyApp.Resource.String.hockeyapp_feedback_email_hint = global::Bit.Android.Resource.String.hockeyapp_feedback_email_hint;
global::HockeyApp.Resource.String.hockeyapp_feedback_email_hint_required = global::Bit.Android.Resource.String.hockeyapp_feedback_email_hint_required;
global::HockeyApp.Resource.String.hockeyapp_feedback_failed_text = global::Bit.Android.Resource.String.hockeyapp_feedback_failed_text;
global::HockeyApp.Resource.String.hockeyapp_feedback_failed_title = global::Bit.Android.Resource.String.hockeyapp_feedback_failed_title;
global::HockeyApp.Resource.String.hockeyapp_feedback_fetching_feedback_text = global::Bit.Android.Resource.String.hockeyapp_feedback_fetching_feedback_text;
@@ -138,7 +142,9 @@ namespace Bit.Android
global::HockeyApp.Resource.String.hockeyapp_feedback_last_updated_text = global::Bit.Android.Resource.String.hockeyapp_feedback_last_updated_text;
global::HockeyApp.Resource.String.hockeyapp_feedback_max_attachments_allowed = global::Bit.Android.Resource.String.hockeyapp_feedback_max_attachments_allowed;
global::HockeyApp.Resource.String.hockeyapp_feedback_message_hint = global::Bit.Android.Resource.String.hockeyapp_feedback_message_hint;
global::HockeyApp.Resource.String.hockeyapp_feedback_message_hint_required = global::Bit.Android.Resource.String.hockeyapp_feedback_message_hint_required;
global::HockeyApp.Resource.String.hockeyapp_feedback_name_hint = global::Bit.Android.Resource.String.hockeyapp_feedback_name_hint;
global::HockeyApp.Resource.String.hockeyapp_feedback_name_hint_required = global::Bit.Android.Resource.String.hockeyapp_feedback_name_hint_required;
global::HockeyApp.Resource.String.hockeyapp_feedback_refresh_button_text = global::Bit.Android.Resource.String.hockeyapp_feedback_refresh_button_text;
global::HockeyApp.Resource.String.hockeyapp_feedback_response_button_text = global::Bit.Android.Resource.String.hockeyapp_feedback_response_button_text;
global::HockeyApp.Resource.String.hockeyapp_feedback_select_file = global::Bit.Android.Resource.String.hockeyapp_feedback_select_file;
@@ -147,7 +153,9 @@ namespace Bit.Android
global::HockeyApp.Resource.String.hockeyapp_feedback_send_generic_error = global::Bit.Android.Resource.String.hockeyapp_feedback_send_generic_error;
global::HockeyApp.Resource.String.hockeyapp_feedback_send_network_error = global::Bit.Android.Resource.String.hockeyapp_feedback_send_network_error;
global::HockeyApp.Resource.String.hockeyapp_feedback_sending_feedback_text = global::Bit.Android.Resource.String.hockeyapp_feedback_sending_feedback_text;
global::HockeyApp.Resource.String.hockeyapp_feedback_sent_toast = global::Bit.Android.Resource.String.hockeyapp_feedback_sent_toast;
global::HockeyApp.Resource.String.hockeyapp_feedback_subject_hint = global::Bit.Android.Resource.String.hockeyapp_feedback_subject_hint;
global::HockeyApp.Resource.String.hockeyapp_feedback_subject_hint_required = global::Bit.Android.Resource.String.hockeyapp_feedback_subject_hint_required;
global::HockeyApp.Resource.String.hockeyapp_feedback_title = global::Bit.Android.Resource.String.hockeyapp_feedback_title;
global::HockeyApp.Resource.String.hockeyapp_feedback_validate_email_empty = global::Bit.Android.Resource.String.hockeyapp_feedback_validate_email_empty;
global::HockeyApp.Resource.String.hockeyapp_feedback_validate_email_error = global::Bit.Android.Resource.String.hockeyapp_feedback_validate_email_error;
@@ -155,11 +163,13 @@ namespace Bit.Android
global::HockeyApp.Resource.String.hockeyapp_feedback_validate_subject_error = global::Bit.Android.Resource.String.hockeyapp_feedback_validate_subject_error;
global::HockeyApp.Resource.String.hockeyapp_feedback_validate_text_error = global::Bit.Android.Resource.String.hockeyapp_feedback_validate_text_error;
global::HockeyApp.Resource.String.hockeyapp_login_email_hint = global::Bit.Android.Resource.String.hockeyapp_login_email_hint;
global::HockeyApp.Resource.String.hockeyapp_login_email_hint_required = global::Bit.Android.Resource.String.hockeyapp_login_email_hint_required;
global::HockeyApp.Resource.String.hockeyapp_login_headline_text = global::Bit.Android.Resource.String.hockeyapp_login_headline_text;
global::HockeyApp.Resource.String.hockeyapp_login_headline_text_email_only = global::Bit.Android.Resource.String.hockeyapp_login_headline_text_email_only;
global::HockeyApp.Resource.String.hockeyapp_login_login_button_text = global::Bit.Android.Resource.String.hockeyapp_login_login_button_text;
global::HockeyApp.Resource.String.hockeyapp_login_missing_credentials_toast = global::Bit.Android.Resource.String.hockeyapp_login_missing_credentials_toast;
global::HockeyApp.Resource.String.hockeyapp_login_password_hint = global::Bit.Android.Resource.String.hockeyapp_login_password_hint;
global::HockeyApp.Resource.String.hockeyapp_login_password_hint_required = global::Bit.Android.Resource.String.hockeyapp_login_password_hint_required;
global::HockeyApp.Resource.String.hockeyapp_paint_dialog_message = global::Bit.Android.Resource.String.hockeyapp_paint_dialog_message;
global::HockeyApp.Resource.String.hockeyapp_paint_dialog_negative_button = global::Bit.Android.Resource.String.hockeyapp_paint_dialog_negative_button;
global::HockeyApp.Resource.String.hockeyapp_paint_dialog_neutral_button = global::Bit.Android.Resource.String.hockeyapp_paint_dialog_neutral_button;
@@ -2307,508 +2317,514 @@ namespace Bit.Android
public const int cloudup = 2130837584;
// aapt resource value: 0x7f020051
public const int cogs = 2130837585;
public const int cog = 2130837585;
// aapt resource value: 0x7f020052
public const int cogs_selected = 2130837586;
public const int cogs = 2130837586;
// aapt resource value: 0x7f020053
public const int common_full_open_on_phone = 2130837587;
public const int cogs_selected = 2130837587;
// aapt resource value: 0x7f020054
public const int common_google_signin_btn_icon_dark = 2130837588;
public const int common_full_open_on_phone = 2130837588;
// aapt resource value: 0x7f020055
public const int common_google_signin_btn_icon_dark_disabled = 2130837589;
public const int common_google_signin_btn_icon_dark = 2130837589;
// aapt resource value: 0x7f020056
public const int common_google_signin_btn_icon_dark_focused = 2130837590;
public const int common_google_signin_btn_icon_dark_disabled = 2130837590;
// aapt resource value: 0x7f020057
public const int common_google_signin_btn_icon_dark_normal = 2130837591;
public const int common_google_signin_btn_icon_dark_focused = 2130837591;
// aapt resource value: 0x7f020058
public const int common_google_signin_btn_icon_dark_pressed = 2130837592;
public const int common_google_signin_btn_icon_dark_normal = 2130837592;
// aapt resource value: 0x7f020059
public const int common_google_signin_btn_icon_light = 2130837593;
public const int common_google_signin_btn_icon_dark_pressed = 2130837593;
// aapt resource value: 0x7f02005a
public const int common_google_signin_btn_icon_light_disabled = 2130837594;
public const int common_google_signin_btn_icon_light = 2130837594;
// aapt resource value: 0x7f02005b
public const int common_google_signin_btn_icon_light_focused = 2130837595;
public const int common_google_signin_btn_icon_light_disabled = 2130837595;
// aapt resource value: 0x7f02005c
public const int common_google_signin_btn_icon_light_normal = 2130837596;
public const int common_google_signin_btn_icon_light_focused = 2130837596;
// aapt resource value: 0x7f02005d
public const int common_google_signin_btn_icon_light_pressed = 2130837597;
public const int common_google_signin_btn_icon_light_normal = 2130837597;
// aapt resource value: 0x7f02005e
public const int common_google_signin_btn_text_dark = 2130837598;
public const int common_google_signin_btn_icon_light_pressed = 2130837598;
// aapt resource value: 0x7f02005f
public const int common_google_signin_btn_text_dark_disabled = 2130837599;
public const int common_google_signin_btn_text_dark = 2130837599;
// aapt resource value: 0x7f020060
public const int common_google_signin_btn_text_dark_focused = 2130837600;
public const int common_google_signin_btn_text_dark_disabled = 2130837600;
// aapt resource value: 0x7f020061
public const int common_google_signin_btn_text_dark_normal = 2130837601;
public const int common_google_signin_btn_text_dark_focused = 2130837601;
// aapt resource value: 0x7f020062
public const int common_google_signin_btn_text_dark_pressed = 2130837602;
public const int common_google_signin_btn_text_dark_normal = 2130837602;
// aapt resource value: 0x7f020063
public const int common_google_signin_btn_text_light = 2130837603;
public const int common_google_signin_btn_text_dark_pressed = 2130837603;
// aapt resource value: 0x7f020064
public const int common_google_signin_btn_text_light_disabled = 2130837604;
public const int common_google_signin_btn_text_light = 2130837604;
// aapt resource value: 0x7f020065
public const int common_google_signin_btn_text_light_focused = 2130837605;
public const int common_google_signin_btn_text_light_disabled = 2130837605;
// aapt resource value: 0x7f020066
public const int common_google_signin_btn_text_light_normal = 2130837606;
public const int common_google_signin_btn_text_light_focused = 2130837606;
// aapt resource value: 0x7f020067
public const int common_google_signin_btn_text_light_pressed = 2130837607;
public const int common_google_signin_btn_text_light_normal = 2130837607;
// aapt resource value: 0x7f020068
public const int common_ic_googleplayservices = 2130837608;
public const int common_google_signin_btn_text_light_pressed = 2130837608;
// aapt resource value: 0x7f020069
public const int common_plus_signin_btn_icon_dark = 2130837609;
public const int common_ic_googleplayservices = 2130837609;
// aapt resource value: 0x7f02006a
public const int common_plus_signin_btn_icon_dark_disabled = 2130837610;
public const int common_plus_signin_btn_icon_dark = 2130837610;
// aapt resource value: 0x7f02006b
public const int common_plus_signin_btn_icon_dark_focused = 2130837611;
public const int common_plus_signin_btn_icon_dark_disabled = 2130837611;
// aapt resource value: 0x7f02006c
public const int common_plus_signin_btn_icon_dark_normal = 2130837612;
public const int common_plus_signin_btn_icon_dark_focused = 2130837612;
// aapt resource value: 0x7f02006d
public const int common_plus_signin_btn_icon_dark_pressed = 2130837613;
public const int common_plus_signin_btn_icon_dark_normal = 2130837613;
// aapt resource value: 0x7f02006e
public const int common_plus_signin_btn_icon_light = 2130837614;
public const int common_plus_signin_btn_icon_dark_pressed = 2130837614;
// aapt resource value: 0x7f02006f
public const int common_plus_signin_btn_icon_light_disabled = 2130837615;
public const int common_plus_signin_btn_icon_light = 2130837615;
// aapt resource value: 0x7f020070
public const int common_plus_signin_btn_icon_light_focused = 2130837616;
public const int common_plus_signin_btn_icon_light_disabled = 2130837616;
// aapt resource value: 0x7f020071
public const int common_plus_signin_btn_icon_light_normal = 2130837617;
public const int common_plus_signin_btn_icon_light_focused = 2130837617;
// aapt resource value: 0x7f020072
public const int common_plus_signin_btn_icon_light_pressed = 2130837618;
public const int common_plus_signin_btn_icon_light_normal = 2130837618;
// aapt resource value: 0x7f020073
public const int common_plus_signin_btn_text_dark = 2130837619;
public const int common_plus_signin_btn_icon_light_pressed = 2130837619;
// aapt resource value: 0x7f020074
public const int common_plus_signin_btn_text_dark_disabled = 2130837620;
public const int common_plus_signin_btn_text_dark = 2130837620;
// aapt resource value: 0x7f020075
public const int common_plus_signin_btn_text_dark_focused = 2130837621;
public const int common_plus_signin_btn_text_dark_disabled = 2130837621;
// aapt resource value: 0x7f020076
public const int common_plus_signin_btn_text_dark_normal = 2130837622;
public const int common_plus_signin_btn_text_dark_focused = 2130837622;
// aapt resource value: 0x7f020077
public const int common_plus_signin_btn_text_dark_pressed = 2130837623;
public const int common_plus_signin_btn_text_dark_normal = 2130837623;
// aapt resource value: 0x7f020078
public const int common_plus_signin_btn_text_light = 2130837624;
public const int common_plus_signin_btn_text_dark_pressed = 2130837624;
// aapt resource value: 0x7f020079
public const int common_plus_signin_btn_text_light_disabled = 2130837625;
public const int common_plus_signin_btn_text_light = 2130837625;
// aapt resource value: 0x7f02007a
public const int common_plus_signin_btn_text_light_focused = 2130837626;
public const int common_plus_signin_btn_text_light_disabled = 2130837626;
// aapt resource value: 0x7f02007b
public const int common_plus_signin_btn_text_light_normal = 2130837627;
public const int common_plus_signin_btn_text_light_focused = 2130837627;
// aapt resource value: 0x7f02007c
public const int common_plus_signin_btn_text_light_pressed = 2130837628;
public const int common_plus_signin_btn_text_light_normal = 2130837628;
// aapt resource value: 0x7f02007d
public const int design_fab_background = 2130837629;
public const int common_plus_signin_btn_text_light_pressed = 2130837629;
// aapt resource value: 0x7f02007e
public const int design_snackbar_background = 2130837630;
public const int design_fab_background = 2130837630;
// aapt resource value: 0x7f02007f
public const int download = 2130837631;
public const int design_snackbar_background = 2130837631;
// aapt resource value: 0x7f020080
public const int envelope = 2130837632;
public const int download = 2130837632;
// aapt resource value: 0x7f020081
public const int eye = 2130837633;
public const int envelope = 2130837633;
// aapt resource value: 0x7f020082
public const int eye_slash = 2130837634;
public const int eye = 2130837634;
// aapt resource value: 0x7f020083
public const int fa_lock = 2130837635;
public const int eye_slash = 2130837635;
// aapt resource value: 0x7f020084
public const int fa_lock_selected = 2130837636;
public const int fa_lock = 2130837636;
// aapt resource value: 0x7f020085
public const int fingerprint = 2130837637;
public const int fa_lock_selected = 2130837637;
// aapt resource value: 0x7f020086
public const int fingerprint_white = 2130837638;
public const int fingerprint = 2130837638;
// aapt resource value: 0x7f020087
public const int folder = 2130837639;
public const int fingerprint_white = 2130837639;
// aapt resource value: 0x7f020088
public const int globe = 2130837640;
public const int folder = 2130837640;
// aapt resource value: 0x7f020089
public const int hockeyapp_btn_background = 2130837641;
public const int globe = 2130837641;
// aapt resource value: 0x7f02008a
public const int ic_audiotrack = 2130837642;
public const int hockeyapp_btn_background = 2130837642;
// aapt resource value: 0x7f02008b
public const int ic_audiotrack_light = 2130837643;
public const int ic_audiotrack = 2130837643;
// aapt resource value: 0x7f02008c
public const int ic_bluetooth_grey = 2130837644;
public const int ic_audiotrack_light = 2130837644;
// aapt resource value: 0x7f02008d
public const int ic_bluetooth_white = 2130837645;
public const int ic_bluetooth_grey = 2130837645;
// aapt resource value: 0x7f02008e
public const int ic_cast_dark = 2130837646;
public const int ic_bluetooth_white = 2130837646;
// aapt resource value: 0x7f02008f
public const int ic_cast_disabled_light = 2130837647;
public const int ic_cast_dark = 2130837647;
// aapt resource value: 0x7f020090
public const int ic_cast_grey = 2130837648;
public const int ic_cast_disabled_light = 2130837648;
// aapt resource value: 0x7f020091
public const int ic_cast_light = 2130837649;
public const int ic_cast_grey = 2130837649;
// aapt resource value: 0x7f020092
public const int ic_cast_off_light = 2130837650;
public const int ic_cast_light = 2130837650;
// aapt resource value: 0x7f020093
public const int ic_cast_on_0_light = 2130837651;
public const int ic_cast_off_light = 2130837651;
// aapt resource value: 0x7f020094
public const int ic_cast_on_1_light = 2130837652;
public const int ic_cast_on_0_light = 2130837652;
// aapt resource value: 0x7f020095
public const int ic_cast_on_2_light = 2130837653;
public const int ic_cast_on_1_light = 2130837653;
// aapt resource value: 0x7f020096
public const int ic_cast_on_light = 2130837654;
public const int ic_cast_on_2_light = 2130837654;
// aapt resource value: 0x7f020097
public const int ic_cast_white = 2130837655;
public const int ic_cast_on_light = 2130837655;
// aapt resource value: 0x7f020098
public const int ic_close_dark = 2130837656;
public const int ic_cast_white = 2130837656;
// aapt resource value: 0x7f020099
public const int ic_close_light = 2130837657;
public const int ic_close_dark = 2130837657;
// aapt resource value: 0x7f02009a
public const int ic_collapse = 2130837658;
public const int ic_close_light = 2130837658;
// aapt resource value: 0x7f02009b
public const int ic_collapse_00000 = 2130837659;
public const int ic_collapse = 2130837659;
// aapt resource value: 0x7f02009c
public const int ic_collapse_00001 = 2130837660;
public const int ic_collapse_00000 = 2130837660;
// aapt resource value: 0x7f02009d
public const int ic_collapse_00002 = 2130837661;
public const int ic_collapse_00001 = 2130837661;
// aapt resource value: 0x7f02009e
public const int ic_collapse_00003 = 2130837662;
public const int ic_collapse_00002 = 2130837662;
// aapt resource value: 0x7f02009f
public const int ic_collapse_00004 = 2130837663;
public const int ic_collapse_00003 = 2130837663;
// aapt resource value: 0x7f0200a0
public const int ic_collapse_00005 = 2130837664;
public const int ic_collapse_00004 = 2130837664;
// aapt resource value: 0x7f0200a1
public const int ic_collapse_00006 = 2130837665;
public const int ic_collapse_00005 = 2130837665;
// aapt resource value: 0x7f0200a2
public const int ic_collapse_00007 = 2130837666;
public const int ic_collapse_00006 = 2130837666;
// aapt resource value: 0x7f0200a3
public const int ic_collapse_00008 = 2130837667;
public const int ic_collapse_00007 = 2130837667;
// aapt resource value: 0x7f0200a4
public const int ic_collapse_00009 = 2130837668;
public const int ic_collapse_00008 = 2130837668;
// aapt resource value: 0x7f0200a5
public const int ic_collapse_00010 = 2130837669;
public const int ic_collapse_00009 = 2130837669;
// aapt resource value: 0x7f0200a6
public const int ic_collapse_00011 = 2130837670;
public const int ic_collapse_00010 = 2130837670;
// aapt resource value: 0x7f0200a7
public const int ic_collapse_00012 = 2130837671;
public const int ic_collapse_00011 = 2130837671;
// aapt resource value: 0x7f0200a8
public const int ic_collapse_00013 = 2130837672;
public const int ic_collapse_00012 = 2130837672;
// aapt resource value: 0x7f0200a9
public const int ic_collapse_00014 = 2130837673;
public const int ic_collapse_00013 = 2130837673;
// aapt resource value: 0x7f0200aa
public const int ic_collapse_00015 = 2130837674;
public const int ic_collapse_00014 = 2130837674;
// aapt resource value: 0x7f0200ab
public const int ic_errorstatus = 2130837675;
public const int ic_collapse_00015 = 2130837675;
// aapt resource value: 0x7f0200ac
public const int ic_expand = 2130837676;
public const int ic_errorstatus = 2130837676;
// aapt resource value: 0x7f0200ad
public const int ic_expand_00000 = 2130837677;
public const int ic_expand = 2130837677;
// aapt resource value: 0x7f0200ae
public const int ic_expand_00001 = 2130837678;
public const int ic_expand_00000 = 2130837678;
// aapt resource value: 0x7f0200af
public const int ic_expand_00002 = 2130837679;
public const int ic_expand_00001 = 2130837679;
// aapt resource value: 0x7f0200b0
public const int ic_expand_00003 = 2130837680;
public const int ic_expand_00002 = 2130837680;
// aapt resource value: 0x7f0200b1
public const int ic_expand_00004 = 2130837681;
public const int ic_expand_00003 = 2130837681;
// aapt resource value: 0x7f0200b2
public const int ic_expand_00005 = 2130837682;
public const int ic_expand_00004 = 2130837682;
// aapt resource value: 0x7f0200b3
public const int ic_expand_00006 = 2130837683;
public const int ic_expand_00005 = 2130837683;
// aapt resource value: 0x7f0200b4
public const int ic_expand_00007 = 2130837684;
public const int ic_expand_00006 = 2130837684;
// aapt resource value: 0x7f0200b5
public const int ic_expand_00008 = 2130837685;
public const int ic_expand_00007 = 2130837685;
// aapt resource value: 0x7f0200b6
public const int ic_expand_00009 = 2130837686;
public const int ic_expand_00008 = 2130837686;
// aapt resource value: 0x7f0200b7
public const int ic_expand_00010 = 2130837687;
public const int ic_expand_00009 = 2130837687;
// aapt resource value: 0x7f0200b8
public const int ic_expand_00011 = 2130837688;
public const int ic_expand_00010 = 2130837688;
// aapt resource value: 0x7f0200b9
public const int ic_expand_00012 = 2130837689;
public const int ic_expand_00011 = 2130837689;
// aapt resource value: 0x7f0200ba
public const int ic_expand_00013 = 2130837690;
public const int ic_expand_00012 = 2130837690;
// aapt resource value: 0x7f0200bb
public const int ic_expand_00014 = 2130837691;
public const int ic_expand_00013 = 2130837691;
// aapt resource value: 0x7f0200bc
public const int ic_expand_00015 = 2130837692;
public const int ic_expand_00014 = 2130837692;
// aapt resource value: 0x7f0200bd
public const int ic_media_pause = 2130837693;
public const int ic_expand_00015 = 2130837693;
// aapt resource value: 0x7f0200be
public const int ic_media_play = 2130837694;
public const int ic_media_pause = 2130837694;
// aapt resource value: 0x7f0200bf
public const int ic_media_route_disabled_mono_dark = 2130837695;
public const int ic_media_play = 2130837695;
// aapt resource value: 0x7f0200c0
public const int ic_media_route_off_mono_dark = 2130837696;
public const int ic_media_route_disabled_mono_dark = 2130837696;
// aapt resource value: 0x7f0200c1
public const int ic_media_route_on_0_mono_dark = 2130837697;
public const int ic_media_route_off_mono_dark = 2130837697;
// aapt resource value: 0x7f0200c2
public const int ic_media_route_on_1_mono_dark = 2130837698;
public const int ic_media_route_on_0_mono_dark = 2130837698;
// aapt resource value: 0x7f0200c3
public const int ic_media_route_on_2_mono_dark = 2130837699;
public const int ic_media_route_on_1_mono_dark = 2130837699;
// aapt resource value: 0x7f0200c4
public const int ic_media_route_on_mono_dark = 2130837700;
public const int ic_media_route_on_2_mono_dark = 2130837700;
// aapt resource value: 0x7f0200c5
public const int ic_pause_dark = 2130837701;
public const int ic_media_route_on_mono_dark = 2130837701;
// aapt resource value: 0x7f0200c6
public const int ic_pause_light = 2130837702;
public const int ic_pause_dark = 2130837702;
// aapt resource value: 0x7f0200c7
public const int ic_play_dark = 2130837703;
public const int ic_pause_light = 2130837703;
// aapt resource value: 0x7f0200c8
public const int ic_play_light = 2130837704;
public const int ic_play_dark = 2130837704;
// aapt resource value: 0x7f0200c9
public const int ic_speaker_dark = 2130837705;
public const int ic_play_light = 2130837705;
// aapt resource value: 0x7f0200ca
public const int ic_speaker_group_dark = 2130837706;
public const int ic_speaker_dark = 2130837706;
// aapt resource value: 0x7f0200cb
public const int ic_speaker_group_light = 2130837707;
public const int ic_speaker_group_dark = 2130837707;
// aapt resource value: 0x7f0200cc
public const int ic_speaker_light = 2130837708;
public const int ic_speaker_group_light = 2130837708;
// aapt resource value: 0x7f0200cd
public const int ic_successstatus = 2130837709;
public const int ic_speaker_light = 2130837709;
// aapt resource value: 0x7f0200ce
public const int ic_tv_dark = 2130837710;
public const int ic_successstatus = 2130837710;
// aapt resource value: 0x7f0200cf
public const int ic_tv_light = 2130837711;
public const int ic_tv_dark = 2130837711;
// aapt resource value: 0x7f0200d0
public const int icon = 2130837712;
public const int ic_tv_light = 2130837712;
// aapt resource value: 0x7f0200d1
public const int ion_chevron_right = 2130837713;
public const int icon = 2130837713;
// aapt resource value: 0x7f0200d2
public const int lightbulb = 2130837714;
public const int ion_chevron_right = 2130837714;
// aapt resource value: 0x7f0200d3
public const int list_selector = 2130837715;
public const int lightbulb = 2130837715;
// aapt resource value: 0x7f0200d4
public const int @lock = 2130837716;
public const int list_selector = 2130837716;
// aapt resource value: 0x7f0200d5
public const int logo = 2130837717;
public const int @lock = 2130837717;
// aapt resource value: 0x7f0200d6
public const int more = 2130837718;
public const int logo = 2130837718;
// aapt resource value: 0x7f0200d7
public const int mr_dialog_material_background_dark = 2130837719;
public const int more = 2130837719;
// aapt resource value: 0x7f0200d8
public const int mr_dialog_material_background_light = 2130837720;
public const int mr_dialog_material_background_dark = 2130837720;
// aapt resource value: 0x7f0200d9
public const int mr_ic_audiotrack_light = 2130837721;
public const int mr_dialog_material_background_light = 2130837721;
// aapt resource value: 0x7f0200da
public const int mr_ic_cast_dark = 2130837722;
public const int mr_ic_audiotrack_light = 2130837722;
// aapt resource value: 0x7f0200db
public const int mr_ic_cast_light = 2130837723;
public const int mr_ic_cast_dark = 2130837723;
// aapt resource value: 0x7f0200dc
public const int mr_ic_close_dark = 2130837724;
public const int mr_ic_cast_light = 2130837724;
// aapt resource value: 0x7f0200dd
public const int mr_ic_close_light = 2130837725;
public const int mr_ic_close_dark = 2130837725;
// aapt resource value: 0x7f0200de
public const int mr_ic_media_route_connecting_mono_dark = 2130837726;
public const int mr_ic_close_light = 2130837726;
// aapt resource value: 0x7f0200df
public const int mr_ic_media_route_connecting_mono_light = 2130837727;
public const int mr_ic_media_route_connecting_mono_dark = 2130837727;
// aapt resource value: 0x7f0200e0
public const int mr_ic_media_route_mono_dark = 2130837728;
public const int mr_ic_media_route_connecting_mono_light = 2130837728;
// aapt resource value: 0x7f0200e1
public const int mr_ic_media_route_mono_light = 2130837729;
public const int mr_ic_media_route_mono_dark = 2130837729;
// aapt resource value: 0x7f0200e2
public const int mr_ic_pause_dark = 2130837730;
public const int mr_ic_media_route_mono_light = 2130837730;
// aapt resource value: 0x7f0200e3
public const int mr_ic_pause_light = 2130837731;
public const int mr_ic_pause_dark = 2130837731;
// aapt resource value: 0x7f0200e4
public const int mr_ic_play_dark = 2130837732;
public const int mr_ic_pause_light = 2130837732;
// aapt resource value: 0x7f0200e5
public const int mr_ic_play_light = 2130837733;
public const int mr_ic_play_dark = 2130837733;
// aapt resource value: 0x7f0200e6
public const int notification_sm = 2130837734;
// aapt resource value: 0x7f0200f8
public const int notification_template_icon_bg = 2130837752;
public const int mr_ic_play_light = 2130837734;
// aapt resource value: 0x7f0200e7
public const int paperclip = 2130837735;
public const int notification_sm = 2130837735;
// aapt resource value: 0x7f0200fa
public const int notification_template_icon_bg = 2130837754;
// aapt resource value: 0x7f0200e8
public const int plus = 2130837736;
public const int paperclip = 2130837736;
// aapt resource value: 0x7f0200e9
public const int refresh = 2130837737;
public const int plus = 2130837737;
// aapt resource value: 0x7f0200ea
public const int roundedbg = 2130837738;
public const int refresh = 2130837738;
// aapt resource value: 0x7f0200eb
public const int roundedbgdark = 2130837739;
public const int roundedbg = 2130837739;
// aapt resource value: 0x7f0200ec
public const int search = 2130837740;
public const int roundedbgdark = 2130837740;
// aapt resource value: 0x7f0200ed
public const int share = 2130837741;
public const int search = 2130837741;
// aapt resource value: 0x7f0200ee
public const int share_tools = 2130837742;
public const int share = 2130837742;
// aapt resource value: 0x7f0200ef
public const int splash_screen = 2130837743;
public const int share_tools = 2130837743;
// aapt resource value: 0x7f0200f0
public const int star = 2130837744;
public const int shield = 2130837744;
// aapt resource value: 0x7f0200f1
public const int star_selected = 2130837745;
public const int splash_screen = 2130837745;
// aapt resource value: 0x7f0200f2
public const int tools = 2130837746;
public const int star = 2130837746;
// aapt resource value: 0x7f0200f3
public const int tools_selected = 2130837747;
public const int star_selected = 2130837747;
// aapt resource value: 0x7f0200f4
public const int trash = 2130837748;
public const int tools = 2130837748;
// aapt resource value: 0x7f0200f5
public const int upload = 2130837749;
public const int tools_selected = 2130837749;
// aapt resource value: 0x7f0200f6
public const int user = 2130837750;
public const int trash = 2130837750;
// aapt resource value: 0x7f0200f7
public const int yubikey = 2130837751;
public const int upload = 2130837751;
// aapt resource value: 0x7f0200f8
public const int user = 2130837752;
// aapt resource value: 0x7f0200f9
public const int yubikey = 2130837753;
static Drawable()
{
@@ -3737,12 +3753,15 @@ namespace Bit.Android
// aapt resource value: 0x7f080047
public const int ApplicationName = 2131230791;
// aapt resource value: 0x7f08008f
public const int AutoFillServiceDescription = 2131230863;
// aapt resource value: 0x7f080099
public const int AutoFillServiceDescription = 2131230873;
// aapt resource value: 0x7f080046
public const int Hello = 2131230790;
// aapt resource value: 0x7f08009a
public const int MyVault = 2131230874;
// aapt resource value: 0x7f08002e
public const int abc_action_bar_home_description = 2131230766;
@@ -3960,160 +3979,190 @@ namespace Bit.Android
public const int hockeyapp_feedback_attach_picture = 2131230810;
// aapt resource value: 0x7f08005b
public const int hockeyapp_feedback_attachment_button_text = 2131230811;
public const int hockeyapp_feedback_attachment_added = 2131230811;
// aapt resource value: 0x7f08005c
public const int hockeyapp_feedback_attachment_error = 2131230812;
public const int hockeyapp_feedback_attachment_button_text = 2131230812;
// aapt resource value: 0x7f08005d
public const int hockeyapp_feedback_attachment_loading = 2131230813;
public const int hockeyapp_feedback_attachment_error = 2131230813;
// aapt resource value: 0x7f08005e
public const int hockeyapp_feedback_email_hint = 2131230814;
public const int hockeyapp_feedback_attachment_loading = 2131230814;
// aapt resource value: 0x7f08005f
public const int hockeyapp_feedback_failed_text = 2131230815;
public const int hockeyapp_feedback_attachment_remove_description = 2131230815;
// aapt resource value: 0x7f080060
public const int hockeyapp_feedback_failed_title = 2131230816;
public const int hockeyapp_feedback_attachment_removed = 2131230816;
// aapt resource value: 0x7f080061
public const int hockeyapp_feedback_fetching_feedback_text = 2131230817;
public const int hockeyapp_feedback_email_hint = 2131230817;
// aapt resource value: 0x7f080062
public const int hockeyapp_feedback_generic_error = 2131230818;
public const int hockeyapp_feedback_email_hint_required = 2131230818;
// aapt resource value: 0x7f080063
public const int hockeyapp_feedback_last_updated_text = 2131230819;
public const int hockeyapp_feedback_failed_text = 2131230819;
// aapt resource value: 0x7f080064
public const int hockeyapp_feedback_max_attachments_allowed = 2131230820;
public const int hockeyapp_feedback_failed_title = 2131230820;
// aapt resource value: 0x7f080065
public const int hockeyapp_feedback_message_hint = 2131230821;
public const int hockeyapp_feedback_fetching_feedback_text = 2131230821;
// aapt resource value: 0x7f080066
public const int hockeyapp_feedback_name_hint = 2131230822;
public const int hockeyapp_feedback_generic_error = 2131230822;
// aapt resource value: 0x7f080067
public const int hockeyapp_feedback_refresh_button_text = 2131230823;
public const int hockeyapp_feedback_last_updated_text = 2131230823;
// aapt resource value: 0x7f080068
public const int hockeyapp_feedback_response_button_text = 2131230824;
public const int hockeyapp_feedback_max_attachments_allowed = 2131230824;
// aapt resource value: 0x7f080069
public const int hockeyapp_feedback_select_file = 2131230825;
public const int hockeyapp_feedback_message_hint = 2131230825;
// aapt resource value: 0x7f08006a
public const int hockeyapp_feedback_select_picture = 2131230826;
public const int hockeyapp_feedback_message_hint_required = 2131230826;
// aapt resource value: 0x7f08006b
public const int hockeyapp_feedback_send_button_text = 2131230827;
public const int hockeyapp_feedback_name_hint = 2131230827;
// aapt resource value: 0x7f08006c
public const int hockeyapp_feedback_send_generic_error = 2131230828;
public const int hockeyapp_feedback_name_hint_required = 2131230828;
// aapt resource value: 0x7f08006d
public const int hockeyapp_feedback_send_network_error = 2131230829;
public const int hockeyapp_feedback_refresh_button_text = 2131230829;
// aapt resource value: 0x7f08006e
public const int hockeyapp_feedback_sending_feedback_text = 2131230830;
public const int hockeyapp_feedback_response_button_text = 2131230830;
// aapt resource value: 0x7f08006f
public const int hockeyapp_feedback_subject_hint = 2131230831;
public const int hockeyapp_feedback_select_file = 2131230831;
// aapt resource value: 0x7f080070
public const int hockeyapp_feedback_title = 2131230832;
public const int hockeyapp_feedback_select_picture = 2131230832;
// aapt resource value: 0x7f080071
public const int hockeyapp_feedback_validate_email_empty = 2131230833;
public const int hockeyapp_feedback_send_button_text = 2131230833;
// aapt resource value: 0x7f080072
public const int hockeyapp_feedback_validate_email_error = 2131230834;
public const int hockeyapp_feedback_send_generic_error = 2131230834;
// aapt resource value: 0x7f080073
public const int hockeyapp_feedback_validate_name_error = 2131230835;
public const int hockeyapp_feedback_send_network_error = 2131230835;
// aapt resource value: 0x7f080074
public const int hockeyapp_feedback_validate_subject_error = 2131230836;
public const int hockeyapp_feedback_sending_feedback_text = 2131230836;
// aapt resource value: 0x7f080075
public const int hockeyapp_feedback_validate_text_error = 2131230837;
public const int hockeyapp_feedback_sent_toast = 2131230837;
// aapt resource value: 0x7f080076
public const int hockeyapp_login_email_hint = 2131230838;
public const int hockeyapp_feedback_subject_hint = 2131230838;
// aapt resource value: 0x7f080077
public const int hockeyapp_login_headline_text = 2131230839;
public const int hockeyapp_feedback_subject_hint_required = 2131230839;
// aapt resource value: 0x7f080078
public const int hockeyapp_login_headline_text_email_only = 2131230840;
public const int hockeyapp_feedback_title = 2131230840;
// aapt resource value: 0x7f080079
public const int hockeyapp_login_login_button_text = 2131230841;
public const int hockeyapp_feedback_validate_email_empty = 2131230841;
// aapt resource value: 0x7f08007a
public const int hockeyapp_login_missing_credentials_toast = 2131230842;
public const int hockeyapp_feedback_validate_email_error = 2131230842;
// aapt resource value: 0x7f08007b
public const int hockeyapp_login_password_hint = 2131230843;
public const int hockeyapp_feedback_validate_name_error = 2131230843;
// aapt resource value: 0x7f08007c
public const int hockeyapp_paint_dialog_message = 2131230844;
public const int hockeyapp_feedback_validate_subject_error = 2131230844;
// aapt resource value: 0x7f08007d
public const int hockeyapp_paint_dialog_negative_button = 2131230845;
public const int hockeyapp_feedback_validate_text_error = 2131230845;
// aapt resource value: 0x7f08007e
public const int hockeyapp_paint_dialog_neutral_button = 2131230846;
public const int hockeyapp_login_email_hint = 2131230846;
// aapt resource value: 0x7f08007f
public const int hockeyapp_paint_dialog_positive_button = 2131230847;
public const int hockeyapp_login_email_hint_required = 2131230847;
// aapt resource value: 0x7f080080
public const int hockeyapp_paint_indicator_toast = 2131230848;
public const int hockeyapp_login_headline_text = 2131230848;
// aapt resource value: 0x7f080081
public const int hockeyapp_paint_menu_clear = 2131230849;
public const int hockeyapp_login_headline_text_email_only = 2131230849;
// aapt resource value: 0x7f080082
public const int hockeyapp_paint_menu_save = 2131230850;
public const int hockeyapp_login_login_button_text = 2131230850;
// aapt resource value: 0x7f080083
public const int hockeyapp_paint_menu_undo = 2131230851;
public const int hockeyapp_login_missing_credentials_toast = 2131230851;
// aapt resource value: 0x7f080084
public const int hockeyapp_permission_dialog_negative_button = 2131230852;
public const int hockeyapp_login_password_hint = 2131230852;
// aapt resource value: 0x7f080085
public const int hockeyapp_permission_dialog_positive_button = 2131230853;
public const int hockeyapp_login_password_hint_required = 2131230853;
// aapt resource value: 0x7f080086
public const int hockeyapp_permission_update_message = 2131230854;
public const int hockeyapp_paint_dialog_message = 2131230854;
// aapt resource value: 0x7f080087
public const int hockeyapp_permission_update_title = 2131230855;
public const int hockeyapp_paint_dialog_negative_button = 2131230855;
// aapt resource value: 0x7f080088
public const int hockeyapp_update_button = 2131230856;
public const int hockeyapp_paint_dialog_neutral_button = 2131230856;
// aapt resource value: 0x7f080089
public const int hockeyapp_update_dialog_message = 2131230857;
public const int hockeyapp_paint_dialog_positive_button = 2131230857;
// aapt resource value: 0x7f08008a
public const int hockeyapp_update_dialog_negative_button = 2131230858;
public const int hockeyapp_paint_indicator_toast = 2131230858;
// aapt resource value: 0x7f08008b
public const int hockeyapp_update_dialog_positive_button = 2131230859;
public const int hockeyapp_paint_menu_clear = 2131230859;
// aapt resource value: 0x7f08008c
public const int hockeyapp_update_dialog_title = 2131230860;
public const int hockeyapp_paint_menu_save = 2131230860;
// aapt resource value: 0x7f08008d
public const int hockeyapp_update_mandatory_toast = 2131230861;
public const int hockeyapp_paint_menu_undo = 2131230861;
// aapt resource value: 0x7f08008e
public const int hockeyapp_update_version_details_label = 2131230862;
public const int hockeyapp_permission_dialog_negative_button = 2131230862;
// aapt resource value: 0x7f08008f
public const int hockeyapp_permission_dialog_positive_button = 2131230863;
// aapt resource value: 0x7f080090
public const int hockeyapp_permission_update_message = 2131230864;
// aapt resource value: 0x7f080091
public const int hockeyapp_permission_update_title = 2131230865;
// aapt resource value: 0x7f080092
public const int hockeyapp_update_button = 2131230866;
// aapt resource value: 0x7f080093
public const int hockeyapp_update_dialog_message = 2131230867;
// aapt resource value: 0x7f080094
public const int hockeyapp_update_dialog_negative_button = 2131230868;
// aapt resource value: 0x7f080095
public const int hockeyapp_update_dialog_positive_button = 2131230869;
// aapt resource value: 0x7f080096
public const int hockeyapp_update_dialog_title = 2131230870;
// aapt resource value: 0x7f080097
public const int hockeyapp_update_mandatory_toast = 2131230871;
// aapt resource value: 0x7f080098
public const int hockeyapp_update_version_details_label = 2131230872;
// aapt resource value: 0x7f080045
public const int library_name = 2131230789;

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -5,4 +5,7 @@
accessibility service by tapping the toggle switch above, then press OK on the confirmation pop-up. You can then press
the back button twice to return to the main bitwarden app.
</string>
<string name="MyVault">
My Vault
</string>
</resources>

View File

@@ -76,7 +76,7 @@ namespace Bit.Android.Services
return TryGetAndMigrate(key);
}
var cs = _settings.GetValueOrDefault<string>(formattedKey);
var cs = _settings.GetValueOrDefault(formattedKey, null);
if(string.IsNullOrWhiteSpace(cs))
{
return null;
@@ -201,7 +201,7 @@ namespace Bit.Android.Services
return null;
}
var encKey = _settings.GetValueOrDefault<string>(aesKey);
var encKey = _settings.GetValueOrDefault(aesKey, null);
if(string.IsNullOrWhiteSpace(encKey))
{
return null;
@@ -312,7 +312,7 @@ namespace Bit.Android.Services
{
try
{
var cs = _settings.GetValueOrDefault<string>(formattedKeyV1);
var cs = _settings.GetValueOrDefault(formattedKeyV1, null);
var value = App.Utilities.Crypto.AesCbcDecrypt(new App.Models.CipherString(cs), aesKeyV1);
Store(key, value);
return value;

View File

@@ -95,7 +95,7 @@ namespace Bit.Android.Services
var pm = CrossCurrentActivity.Current.Activity.PackageManager;
var intent = new Intent(Intent.ActionView);
intent.SetType(mimeType);
var activities = pm.QueryIntentActivities(intent, global::Android.Content.PM.PackageInfoFlags.MatchDefaultOnly);
var activities = pm.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
return (activities?.Count ?? 0) > 0;
}
@@ -139,45 +139,47 @@ namespace Bit.Android.Services
MessagingCenter.Unsubscribe<Application>(Application.Current, "SelectFileCameraPermissionDenied");
var hasStorageWritePermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.WriteExternalStorage);
var hasCameraPermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.Camera);
if(!_cameraPermissionsDenied && !hasStorageWritePermission)
{
AskCameraPermission(Manifest.Permission.WriteExternalStorage);
return Task.FromResult(0);
}
if(!_cameraPermissionsDenied && !hasCameraPermission)
{
AskCameraPermission(Manifest.Permission.Camera);
return Task.FromResult(0);
}
var additionalIntents = new List<IParcelable>();
if(Forms.Context.PackageManager.HasSystemFeature(PackageManager.FeatureCamera))
{
var hasCameraPermission = !_cameraPermissionsDenied && HasPermission(Manifest.Permission.Camera);
if(!_cameraPermissionsDenied && !hasStorageWritePermission)
{
AskCameraPermission(Manifest.Permission.WriteExternalStorage);
return Task.FromResult(0);
}
if(!_cameraPermissionsDenied && !hasCameraPermission)
{
AskCameraPermission(Manifest.Permission.Camera);
return Task.FromResult(0);
}
if(!_cameraPermissionsDenied && hasCameraPermission && hasStorageWritePermission)
{
try
{
var root = new Java.IO.File(global::Android.OS.Environment.ExternalStorageDirectory, "bitwarden");
var file = new Java.IO.File(root, "temp_camera_photo.jpg");
if(!file.Exists())
{
file.ParentFile.Mkdirs();
file.CreateNewFile();
}
var outputFileUri = global::Android.Net.Uri.FromFile(file);
additionalIntents.AddRange(GetCameraIntents(outputFileUri));
}
catch(Java.IO.IOException) { }
}
}
var docIntent = new Intent(Intent.ActionOpenDocument);
docIntent.AddCategory(Intent.CategoryOpenable);
docIntent.SetType("*/*");
var chooserIntent = Intent.CreateChooser(docIntent, AppResources.FileSource);
if(!_cameraPermissionsDenied && hasCameraPermission && hasStorageWritePermission)
{
try
{
var root = new Java.IO.File(global::Android.OS.Environment.ExternalStorageDirectory, "bitwarden");
var file = new Java.IO.File(root, "temp_camera_photo.jpg");
if(!file.Exists())
{
file.ParentFile.Mkdirs();
file.CreateNewFile();
}
var outputFileUri = global::Android.Net.Uri.FromFile(file);
additionalIntents.AddRange(GetCameraIntents(outputFileUri));
}
catch(Java.IO.IOException) { }
}
if(additionalIntents.Count > 0)
{
chooserIntent.PutExtra(Intent.ExtraInitialIntents, additionalIntents.ToArray());

View File

@@ -1,4 +1,5 @@
using Android.App;
using Android.Content.PM;
using Android.OS;
using Bit.App.Abstractions;
@@ -42,5 +43,6 @@ namespace Bit.Android.Services
}
}
public bool NfcEnabled => Utilities.NfcEnabled();
public bool HasCamera => Xamarin.Forms.Forms.Context.PackageManager.HasSystemFeature(PackageManager.FeatureCamera);
}
}

View File

@@ -7,8 +7,8 @@ using System.Threading.Tasks;
namespace Bit.Android
{
[Activity(Theme = "@style/BitwardenTheme.Splash",
MainLauncher = true,
[Activity(Theme = "@style/BitwardenTheme.Splash",
MainLauncher = true,
NoHistory = true,
WindowSoftInputMode = global::Android.Views.SoftInput.StateHidden)]
public class SplashActivity : AppCompatActivity
@@ -23,7 +23,9 @@ namespace Bit.Android
base.OnResume();
var startupWork = new Task(() =>
{
StartActivity(new Intent(Application.Context, typeof(MainActivity)));
var mainIntent = new Intent(Application.Context, typeof(MainActivity));
mainIntent.PutExtra("myVaultTile", Intent.GetBooleanExtra("myVaultTile", false));
StartActivity(mainIntent);
});
startupWork.Start();

View File

@@ -12,7 +12,11 @@
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="SimpleInjector" publicKeyToken="984cb50dea722e99" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.7.0" newVersion="4.0.7.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.8.0" newVersion="4.0.8.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="PInvoke.BCrypt" publicKeyToken="9e300f9f87f04a7a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-0.5.0.0" newVersion="0.5.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -5,28 +5,25 @@
<package id="AndHUD" version="1.2.0" targetFramework="monoandroid60" />
<package id="BouncyCastle" version="1.8.1" targetFramework="monoandroid60" />
<package id="CommonServiceLocator" version="1.3" targetFramework="monoandroid60" />
<package id="HockeySDK.Xamarin" version="4.1.2" targetFramework="monoandroid71" />
<package id="HockeySDK.Xamarin" version="4.1.5" targetFramework="monoandroid71" />
<package id="Microsoft.NETCore.Platforms" version="1.0.1" targetFramework="monoandroid71" />
<package id="Microsoft.Win32.Primitives" version="4.0.1" targetFramework="monoandroid71" />
<package id="NETStandard.Library" version="1.6.0" targetFramework="monoandroid71" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="monoandroid60" />
<package id="PCLCrypto" version="2.0.147" targetFramework="monoandroid60" />
<package id="PInvoke.BCrypt" version="0.3.152" targetFramework="monoandroid60" />
<package id="PInvoke.Kernel32" version="0.3.152" targetFramework="monoandroid60" />
<package id="PInvoke.NCrypt" version="0.3.152" targetFramework="monoandroid60" />
<package id="PInvoke.Windows.Core" version="0.3.152" targetFramework="monoandroid60" />
<package id="PInvoke.BCrypt" version="0.5.97" targetFramework="monoandroid71" />
<package id="PInvoke.Kernel32" version="0.5.97" targetFramework="monoandroid71" />
<package id="PInvoke.NCrypt" version="0.5.97" targetFramework="monoandroid71" />
<package id="PInvoke.Windows.Core" version="0.5.97" targetFramework="monoandroid71" />
<package id="Plugin.CurrentActivity" version="1.0.1" targetFramework="monoandroid60" />
<package id="Plugin.Fingerprint" version="1.4.4" targetFramework="monoandroid71" />
<package id="SimpleInjector" version="4.0.7" targetFramework="monoandroid71" />
<package id="Plugin.Fingerprint" version="1.4.5" targetFramework="monoandroid71" />
<package id="SimpleInjector" version="4.0.8" targetFramework="monoandroid71" />
<package id="Splat" version="1.6.2" targetFramework="monoandroid60" />
<package id="sqlite-net-pcl" version="1.2.1" targetFramework="monoandroid60" />
<package id="SQLitePCL.bundle_green" version="0.9.3" targetFramework="monoandroid60" />
<package id="SQLitePCL.plugin.sqlite3.android" version="0.9.3" targetFramework="monoandroid60" />
<package id="SQLitePCL.raw" version="0.9.3" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.2" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.lib.e_sqlite3.android" version="1.1.2" targetFramework="monoandroid60" />
<package id="SQLitePCLRaw.provider.e_sqlite3.android" version="1.1.2" targetFramework="monoandroid60" />
<package id="sqlite-net-pcl" version="1.4.118" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.lib.e_sqlite3.android" version="1.1.8" targetFramework="monoandroid71" />
<package id="SQLitePCLRaw.provider.e_sqlite3.android" version="1.1.8" targetFramework="monoandroid71" />
<package id="System.AppContext" version="4.1.0" targetFramework="monoandroid71" />
<package id="System.Collections" version="4.0.11" targetFramework="monoandroid71" />
<package id="System.Collections.Concurrent" version="4.0.12" targetFramework="monoandroid71" />
@@ -71,9 +68,9 @@
<package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="monoandroid71" />
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="monoandroid71" />
<package id="Validation" version="2.3.7" targetFramework="monoandroid60" />
<package id="Xam.Plugin.Connectivity" version="2.3.0" targetFramework="monoandroid71" />
<package id="Xam.Plugin.Connectivity" version="3.0.2" targetFramework="monoandroid71" />
<package id="Xam.Plugin.PushNotification" version="1.2.4" targetFramework="monoandroid60" developmentDependency="true" />
<package id="Xam.Plugins.Settings" version="2.5.4" targetFramework="monoandroid71" />
<package id="Xam.Plugins.Settings" version="3.0.1" targetFramework="monoandroid71" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid60" />
@@ -84,7 +81,7 @@
<package id="Xamarin.Android.Support.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.FFImageLoading" version="2.2.9" targetFramework="monoandroid71" />
<package id="Xamarin.FFImageLoading.Forms" version="2.2.9" targetFramework="monoandroid71" />
<package id="Xamarin.Forms" version="2.3.4.231" targetFramework="monoandroid71" />
<package id="Xamarin.Forms" version="2.3.4.267" targetFramework="monoandroid71" />
<package id="Xamarin.GooglePlayServices.Analytics" version="29.0.0.2" targetFramework="monoandroid60" />
<package id="Xamarin.GooglePlayServices.Base" version="29.0.0.2" targetFramework="monoandroid60" />
<package id="Xamarin.GooglePlayServices.Basement" version="29.0.0.2" targetFramework="monoandroid60" />

View File

@@ -10,6 +10,5 @@ namespace Bit.App.Abstractions
Task<ApiResult> PostPasswordHintAsync(PasswordHintRequest requestObj);
Task<ApiResult<DateTime?>> GetAccountRevisionDateAsync();
Task<ApiResult<ProfileResponse>> GetProfileAsync();
Task<ApiResult<KeysResponse>> GetKeys();
}
}

View File

@@ -4,10 +4,8 @@ using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ICipherApiRepository
public interface ICipherApiRepository : IApiRepository<CipherRequest, CipherResponse, string>
{
Task<ApiResult<CipherResponse>> GetByIdAsync(string id);
Task<ApiResult<ListResponse<CipherResponse>>> GetAsync();
Task<ApiResult<CipherResponse>> PostAttachmentAsync(string cipherId, byte[] data, string fileName);
Task<ApiResult> DeleteAttachmentAsync(string cipherId, string attachmentId);
}

View File

@@ -1,11 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ILoginApiRepository : IApiRepository<LoginRequest, LoginResponse, string>
{
}
}

View File

@@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Bit.App.Models.Api;
namespace Bit.App.Abstractions
{
public interface ISyncApiRepository
{
Task<ApiResult<SyncResponse>> Get();
}
}

View File

@@ -10,5 +10,9 @@ namespace Bit.App.Abstractions
bool AutofillPersistNotification { get; set; }
bool AutofillPasswordField { get; set; }
string SecurityStamp { get; set; }
string BaseUrl { get; set; }
string WebVaultUrl { get; set; }
string ApiUrl { get; set; }
string IdentityUrl { get; set; }
}
}

View File

@@ -6,5 +6,6 @@
int Version { get; }
float Scale { get; }
bool NfcEnabled { get; }
bool HasCamera { get; }
}
}

View File

@@ -12,7 +12,7 @@ namespace Bit.App.Abstractions
Task<IEnumerable<Login>> GetAllAsync();
Task<IEnumerable<Login>> GetAllAsync(bool favorites);
Task<Tuple<IEnumerable<Login>, IEnumerable<Login>>> GetAllAsync(string uriString);
Task<ApiResult<LoginResponse>> SaveAsync(Login login);
Task<ApiResult<CipherResponse>> SaveAsync(Login login);
Task<ApiResult> DeleteAsync(string id);
Task<byte[]> DownloadAndDecryptAttachmentAsync(string url, string orgId = null);
Task<ApiResult<CipherResponse>> EncryptAndSaveAttachmentAsync(Login login, byte[] data, string fileName);

View File

@@ -6,8 +6,6 @@ namespace Bit.App.Abstractions
{
string Token { get; set; }
string RefreshToken { get; set; }
[Obsolete("Old auth scheme")]
string AuthBearer { get; set; }
string GetTwoFactorToken(string email);
void SetTwoFactorToken(string email, string token);
DateTime TokenExpiration { get; }

View File

@@ -13,13 +13,12 @@ using Acr.UserDialogs;
using XLabs.Ioc;
using System.Reflection;
using Bit.App.Resources;
using Bit.App.Utilities;
namespace Bit.App
{
public class App : Application
{
private const string LastBuildKey = "LastBuild";
private string _uri;
private readonly IDatabaseService _databaseService;
private readonly IConnectivity _connectivity;
@@ -36,6 +35,7 @@ namespace Bit.App
public App(
string uri,
bool myVault,
IAuthService authService,
IConnectivity connectivity,
IUserDialogs userDialogs,
@@ -72,7 +72,7 @@ namespace Bit.App
}
else if(authService.IsAuthenticated)
{
MainPage = new MainPage();
MainPage = new MainPage(myVault: myVault);
}
else
{
@@ -103,13 +103,7 @@ namespace Bit.App
if(string.IsNullOrWhiteSpace(_uri))
{
var lastBuild = _settings.GetValueOrDefault<string>(LastBuildKey);
if(Utilities.Helpers.InDebugMode() || lastBuild == null || lastBuild != _appInfoService.Build)
{
_settings.AddOrUpdateValue(LastBuildKey, _appInfoService.Build);
_databaseService.CreateTables();
}
Helpers.PerformUpdateTasks(_settings, _appInfoService, _databaseService);
await Task.Run(() => FullSyncAsync()).ConfigureAwait(false);
}
@@ -222,13 +216,13 @@ namespace Bit.App
}
}
private async void Logout(string logoutMessage)
private void Logout(string logoutMessage)
{
_authService.LogOut();
var deviceApiRepository = Resolver.Resolve<IDeviceApiRepository>();
var appIdService = Resolver.Resolve<IAppIdService>();
await Task.Run(() => deviceApiRepository.PutClearTokenAsync(appIdService.AppId)).ConfigureAwait(false);
Task.Run(async () => await deviceApiRepository.PutClearTokenAsync(appIdService.AppId));
_googleAnalyticsService.TrackAppEvent("LoggedOut");

View File

@@ -36,6 +36,7 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Abstractions\Repositories\IAttachmentRepository.cs" />
<Compile Include="Abstractions\Repositories\ISyncApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ITwoFactorApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ISettingsApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IAccountsApiRepository.cs" />
@@ -86,6 +87,7 @@
<Compile Include="Controls\PinControl.cs" />
<Compile Include="Controls\VaultAttachmentsViewCell.cs" />
<Compile Include="Controls\VaultListViewCell.cs" />
<Compile Include="Enums\FieldType.cs" />
<Compile Include="Enums\TwoFactorProviderType.cs" />
<Compile Include="Enums\EncryptionType.cs" />
<Compile Include="Enums\OrganizationUserType.cs" />
@@ -97,13 +99,14 @@
<Compile Include="Abstractions\Services\ILocalizeService.cs" />
<Compile Include="Models\Api\ApiError.cs" />
<Compile Include="Models\Api\ApiResult.cs" />
<Compile Include="Models\Api\FolderDataModel.cs" />
<Compile Include="Models\Api\CipherDataModel.cs" />
<Compile Include="Models\Api\FieldDataModel.cs" />
<Compile Include="Models\Api\Request\DeviceTokenRequest.cs" />
<Compile Include="Models\Api\Request\FolderRequest.cs" />
<Compile Include="Models\Api\Request\DeviceRequest.cs" />
<Compile Include="Models\Api\Request\TwoFactorEmailRequest.cs" />
<Compile Include="Models\Api\Request\RegisterRequest.cs" />
<Compile Include="Models\Api\Request\LoginRequest.cs" />
<Compile Include="Models\Api\Request\CipherRequest.cs" />
<Compile Include="Models\Api\Request\PasswordHintRequest.cs" />
<Compile Include="Models\Api\Request\TokenRequest.cs" />
<Compile Include="Models\Api\Response\AttachmentResponse.cs" />
@@ -113,15 +116,16 @@
<Compile Include="Models\Api\Response\FolderResponse.cs" />
<Compile Include="Models\Api\Response\ListResponse.cs" />
<Compile Include="Models\Api\Response\DeviceResponse.cs" />
<Compile Include="Models\Api\Response\LoginResponse.cs" />
<Compile Include="Models\Api\Response\ProfileOrganizationResponse.cs" />
<Compile Include="Models\Api\Response\KeysResponse.cs" />
<Compile Include="Models\Api\Response\SyncResponse.cs" />
<Compile Include="Models\Api\Response\TokenResponse.cs" />
<Compile Include="Models\Api\Response\ProfileResponse.cs" />
<Compile Include="Models\Api\LoginDataModel.cs" />
<Compile Include="Models\CipherString.cs" />
<Compile Include="Models\Data\AttachmentData.cs" />
<Compile Include="Models\Attachment.cs" />
<Compile Include="Models\Field.cs" />
<Compile Include="Models\Page\VaultAttachmentsPageModel.cs" />
<Compile Include="Models\SymmetricCryptoKey.cs" />
<Compile Include="Models\Data\SettingsData.cs" />
@@ -144,6 +148,7 @@
<Compile Include="Pages\Lock\LockPasswordPage.cs" />
<Compile Include="Pages\LoginTwoFactorPage.cs" />
<Compile Include="Pages\PasswordHintPage.cs" />
<Compile Include="Pages\EnvironmentPage.cs" />
<Compile Include="Pages\RegisterPage.cs" />
<Compile Include="Pages\ScanPage.cs" />
<Compile Include="Pages\Settings\SettingsCreditsPage.cs" />
@@ -163,11 +168,13 @@
<Compile Include="Pages\Settings\SettingsSyncPage.cs" />
<Compile Include="Pages\Settings\SettingsPage.cs" />
<Compile Include="Pages\Settings\SettingsListFoldersPage.cs" />
<Compile Include="Pages\Vault\VaultCustomFieldsPage.cs" />
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
<Compile Include="Pages\Vault\VaultAttachmentsPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
<Compile Include="Repositories\AttachmentRepository.cs" />
<Compile Include="Repositories\SyncApiRepository.cs" />
<Compile Include="Repositories\TwoFactorApiRepository.cs" />
<Compile Include="Repositories\SettingsApiRepository.cs" />
<Compile Include="Repositories\ApiRepository.cs" />
@@ -176,13 +183,11 @@
<Compile Include="Repositories\BaseApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IFolderApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ILoginApiRepository.cs" />
<Compile Include="Abstractions\Repositories\IConnectApiRepository.cs" />
<Compile Include="Repositories\DeviceApiRepository.cs" />
<Compile Include="Repositories\CipherApiRepository.cs" />
<Compile Include="Abstractions\Repositories\ICipherApiRepository.cs" />
<Compile Include="Repositories\SettingsRepository.cs" />
<Compile Include="Repositories\LoginApiRepository.cs" />
<Compile Include="Repositories\FolderApiRepository.cs" />
<Compile Include="Repositories\LoginRepository.cs" />
<Compile Include="Repositories\FolderRepository.cs" />
@@ -193,6 +198,11 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.cs.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.da.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.da.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -223,6 +233,11 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.hr.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.hu.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.hu.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.id.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -238,6 +253,16 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.ja.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.nl.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.nl.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.pl.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.pl.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.pt-BR.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -273,6 +298,21 @@
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.th.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.tr.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.tr.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.uk.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.uk.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.vi.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>AppResources.vi.resx</DependentUpon>
</Compile>
<Compile Include="Resources\AppResources.zh-Hans.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -326,6 +366,10 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.cs.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.da.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.da.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.es.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.es.Designer.cs</LastGenOutput>
@@ -346,6 +390,10 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.hr.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.hu.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.hu.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.id.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.id.Designer.cs</LastGenOutput>
@@ -358,6 +406,14 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.ja.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.nl.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.nl.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.pl.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.pl.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.pt-BR.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.pt-BR.Designer.cs</LastGenOutput>
@@ -386,6 +442,18 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.th.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.tr.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.tr.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.uk.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.uk.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.vi.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.vi.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Resources\AppResources.zh-Hans.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>AppResources.zh-Hans.Designer.cs</LastGenOutput>
@@ -412,8 +480,8 @@
<Reference Include="FFImageLoading.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.FFImageLoading.2.2.9\lib\portable-net45+win8+wpa81+wp8\FFImageLoading.Platform.dll</HintPath>
</Reference>
<Reference Include="HockeySDK, Version=1.0.6288.33979, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.2\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\HockeySDK.dll</HintPath>
<Reference Include="HockeySDK, Version=1.0.6387.33440, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\HockeySDK.Xamarin.4.1.5\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\HockeySDK.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
@@ -430,39 +498,35 @@
<HintPath>..\..\packages\PCLCrypto.2.0.147\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\PCLCrypto.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="PInvoke.BCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.BCrypt.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.BCrypt.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.BCrypt, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.BCrypt.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.BCrypt.dll</HintPath>
</Reference>
<Reference Include="PInvoke.Kernel32, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Kernel32.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Kernel32.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.Kernel32, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Kernel32.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.Kernel32.dll</HintPath>
</Reference>
<Reference Include="PInvoke.NCrypt, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.NCrypt.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.NCrypt.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.NCrypt, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.NCrypt.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.NCrypt.dll</HintPath>
</Reference>
<Reference Include="PInvoke.Windows.Core, Version=0.3.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Windows.Core.0.3.152\lib\portable-net45+win+wpa81+MonoAndroid10+xamarinios10+MonoTouch10\PInvoke.Windows.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="PInvoke.Windows.Core, Version=0.5.0.0, Culture=neutral, PublicKeyToken=9e300f9f87f04a7a, processorArchitecture=MSIL">
<HintPath>..\..\packages\PInvoke.Windows.Core.0.5.97\lib\portable-net45+win8+wpa81\PInvoke.Windows.Core.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Connectivity.dll</HintPath>
<Reference Include="Plugin.Connectivity, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.3.0.2\lib\netstandard1.0\Plugin.Connectivity.dll</HintPath>
</Reference>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.3.0\lib\portable-net45+wp80+win8+wpa81\Plugin.Connectivity.Abstractions.dll</HintPath>
<Reference Include="Plugin.Connectivity.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.3.0.2\lib\netstandard1.0\Plugin.Connectivity.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Fingerprint, Version=1.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.4\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.dll</HintPath>
<Reference Include="Plugin.Fingerprint, Version=1.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.5\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.dll</HintPath>
</Reference>
<Reference Include="Plugin.Fingerprint.Abstractions, Version=1.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.4\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.Abstractions.dll</HintPath>
<Reference Include="Plugin.Fingerprint.Abstractions, Version=1.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Fingerprint.1.4.5\lib\portable-net45+win8+wpa81+wp8\Plugin.Fingerprint.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.dll</HintPath>
<Reference Include="Plugin.Settings, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\netstandard1.0\Plugin.Settings.dll</HintPath>
</Reference>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.4\lib\portable-net45+wp80+win8+wpa81\Plugin.Settings.Abstractions.dll</HintPath>
<Reference Include="Plugin.Settings.Abstractions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.3.0.1\lib\netstandard1.0\Plugin.Settings.Abstractions.dll</HintPath>
</Reference>
<Reference Include="PushNotification.Plugin, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.PushNotification.1.2.4\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10+UAP10\PushNotification.Plugin.dll</HintPath>
@@ -476,42 +540,30 @@
<HintPath>..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite-net, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.2.1\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCL.batteries, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCL.bundle_green.0.9.3\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCL.batteries.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCL.raw, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCL.raw.0.9.3\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCL.raw.dll</HintPath>
<Private>True</Private>
<Reference Include="SQLite-net, Version=1.4.118.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\sqlite-net-pcl.1.4.118\lib\portable-net45+wp8+wpa81+win8+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLite-net.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_green.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_green.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_v2.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.2\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
<Private>True</Private>
<HintPath>..\..\packages\SQLitePCLRaw.core.1.1.8\lib\portable-net45+netcore45+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="Validation, Version=2.3.0.0, Culture=neutral, PublicKeyToken=2fc06f0d701809a7, processorArchitecture=MSIL">
<HintPath>..\..\packages\Validation.2.3.7\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Validation.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.231\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll</HintPath>
<HintPath>..\..\packages\Xamarin.Forms.2.3.4.267\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
<Reference Include="XLabs.Ioc, Version=2.0.5782.12218, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.IoC.2.0.5782\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1+Xamarin.iOS10\XLabs.Ioc.dll</HintPath>
@@ -540,12 +592,12 @@
<Compile Include="Services\PushNotificationListener.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.4.231\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.4.267\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

View File

@@ -3,6 +3,7 @@
public static class Constants
{
public const string AndroidAppProtocol = "androidapp://";
public const string iOSAppProtocol = "iosapp://";
public const string SettingFingerprintUnlockOn = "setting:fingerprintUnlockOn";
public const string SettingPinUnlockOn = "setting:pinUnlockOn";
@@ -33,6 +34,11 @@
public const string Locked = "other:locked";
public const string LastLoginEmail = "other:lastLoginEmail";
public const string LastSync = "other:lastSync";
public const string LastBuildKey = "LastBuild";
public const string BaseUrl = "other:baseUrl";
public const string WebVaultUrl = "other:webVaultUrl";
public const string ApiUrl = "other:apiUrl";
public const string IdentityUrl = "other:identityUrl";
public const int SelectFileRequestCode = 42;
public const int SelectFilePermissionRequestCode = 43;

View File

@@ -62,6 +62,7 @@ namespace Bit.App.Controls
}
base.OnDisappearing();
MessagingCenter.Send(Application.Current, "DismissKeyboard");
}
}
}

View File

@@ -14,7 +14,7 @@ namespace Bit.App.Controls
{
HorizontalTextAlignment = TextAlignment.Center,
FontSize = 35,
FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier")
FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier")
};
Entry = new ExtendedEntry

View File

@@ -4,6 +4,8 @@
{
// Folder deprecated
//Folder = 0,
Login = 1
Login = 1,
SecureNote = 2,
Card = 3
}
}

View File

@@ -0,0 +1,9 @@
namespace Bit.App.Enums
{
public enum FieldType : byte
{
Text = 0,
Hidden = 1,
Boolean = 2
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public abstract class CipherDataModel
{
public string Name { get; set; }
public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using Bit.App.Enums;
namespace Bit.App.Models.Api
{
public class FieldDataModel
{
public FieldType Type { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
}

View File

@@ -1,7 +0,0 @@
namespace Bit.App.Models.Api
{
public class FolderDataModel
{
public string Name { get; set; }
}
}

View File

@@ -1,12 +1,10 @@
namespace Bit.App.Models.Api
{
public class LoginDataModel
public class LoginDataModel : CipherDataModel
{
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
}
}

View File

@@ -0,0 +1,63 @@
using Bit.App.Enums;
using System.Collections.Generic;
using System.Linq;
namespace Bit.App.Models.Api
{
public class CipherRequest
{
public CipherRequest(Login login)
{
Type = CipherType.Login;
OrganizationId = login.OrganizationId;
FolderId = login.FolderId;
Name = login.Name?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Favorite = login.Favorite;
if(login.Fields != null)
{
Fields = login.Fields.Select(f => new FieldDataModel
{
Name = f.Name?.EncryptedString,
Value = f.Value?.EncryptedString,
Type = f.Type
});
}
switch(Type)
{
case CipherType.Login:
Login = new LoginType(login);
break;
default:
break;
}
}
public CipherType Type { get; set; }
public string OrganizationId { get; set; }
public string FolderId { get; set; }
public bool Favorite { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public IEnumerable<FieldDataModel> Fields { get; set; }
public LoginType Login { get; set; }
public class LoginType
{
public LoginType(Login login)
{
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Totp = login.Totp?.EncryptedString;
}
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Totp { get; set; }
}
}
}

View File

@@ -1,28 +0,0 @@
namespace Bit.App.Models.Api
{
public class LoginRequest
{
public LoginRequest(Login login)
{
OrganizationId = login.OrganizationId;
FolderId = login.FolderId;
Name = login.Name?.EncryptedString;
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Totp = login.Totp?.EncryptedString;
Favorite = login.Favorite;
}
public string OrganizationId { get; set; }
public string FolderId { get; set; }
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public bool Favorite { get; set; }
}
}

View File

@@ -10,8 +10,6 @@ namespace Bit.App.Models.Api
public string MasterPasswordHash { get; set; }
public string Token { get; set; }
public TwoFactorProviderType? Provider { get; set; }
[Obsolete]
public string OldAuthBearer { get; set; }
public DeviceRequest Device { get; set; }
public bool Remember { get; set; }
@@ -26,11 +24,6 @@ namespace Bit.App.Models.Api
{ "client_id", "mobile" }
};
if(OldAuthBearer != null)
{
dict.Add("OldAuthBearer", OldAuthBearer);
}
if(Device != null)
{
dict.Add("DeviceType", Device.Type.ToString());

View File

@@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public class LoginResponse
{
public string Id { get; set; }
public string FolderId { get; set; }
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string Name { get; set; }
public string Uri { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<AttachmentResponse> Attachments { get; set; }
public DateTime RevisionDate { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Bit.App.Models.Api
{
public class SyncResponse
{
public ProfileResponse Profile { get; set; }
public IEnumerable<FolderResponse> Folders { get; set; }
public IEnumerable<CipherResponse> Ciphers { get; set; }
public DomainsResponse Domains { get; set; }
}
}

View File

@@ -2,6 +2,8 @@
using SQLite;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using System.Linq;
namespace Bit.App.Models.Data
{
@@ -11,41 +13,6 @@ namespace Bit.App.Models.Data
public LoginData()
{ }
public LoginData(Login login, string userId)
{
Id = login.Id;
FolderId = login.FolderId;
UserId = userId;
OrganizationId = login.OrganizationId;
Name = login.Name?.EncryptedString;
Uri = login.Uri?.EncryptedString;
Username = login.Username?.EncryptedString;
Password = login.Password?.EncryptedString;
Notes = login.Notes?.EncryptedString;
Totp = login?.Notes?.EncryptedString;
Favorite = login.Favorite;
Edit = login.Edit;
OrganizationUseTotp = login.OrganizationUseTotp;
}
public LoginData(LoginResponse login, string userId)
{
Id = login.Id;
FolderId = login.FolderId;
UserId = userId;
OrganizationId = login.OrganizationId;
Name = login.Name;
Uri = login.Uri;
Username = login.Username;
Password = login.Password;
Notes = login.Notes;
Totp = login.Totp;
Favorite = login.Favorite;
RevisionDateTime = login.RevisionDate;
Edit = login.Edit;
OrganizationUseTotp = login.OrganizationUseTotp;
}
public LoginData(CipherResponse cipher, string userId)
{
if(cipher.Type != Enums.CipherType.Login)
@@ -69,6 +36,15 @@ namespace Bit.App.Models.Data
Edit = cipher.Edit;
OrganizationUseTotp = cipher.OrganizationUseTotp;
RevisionDateTime = cipher.RevisionDate;
if(data.Fields != null && data.Fields.Any())
{
try
{
Fields = JsonConvert.SerializeObject(data.Fields);
}
catch(JsonSerializationException) { }
}
}
[PrimaryKey]
@@ -83,6 +59,7 @@ namespace Bit.App.Models.Data
public string Password { get; set; }
public string Notes { get; set; }
public string Totp { get; set; }
public string Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }

View File

@@ -4,12 +4,18 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Bit.App.Models
{
// ref: https://github.com/danesparza/domainname-parser
public class DomainName
{
private const string IpRegex = "^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\." +
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
private string _subDomain = string.Empty;
private string _domain = string.Empty;
private string _tld = string.Empty;
@@ -59,6 +65,20 @@ namespace Bit.App.Models
return retval;
}
public static bool TryParseBaseDomain(string domainString, out string result)
{
if(Regex.IsMatch(domainString, IpRegex))
{
result = domainString;
return true;
}
DomainName domain;
var retval = TryParse(domainString, out domain);
result = domain?.BaseDomain;
return retval;
}
private static void ParseDomainName(string domainString, out string TLD, out string SLD, out string SubDomain, out TLDRule MatchingRule)
{
// Make sure domain is all lowercase

21
src/App/Models/Field.cs Normal file
View File

@@ -0,0 +1,21 @@
using Bit.App.Enums;
using Bit.App.Models.Api;
namespace Bit.App.Models
{
public class Field
{
public Field() { }
public Field(FieldDataModel model)
{
Type = model.Type;
Name = new CipherString(model.Name);
Value = new CipherString(model.Value);
}
public FieldType Type { get; set; }
public CipherString Name { get; set; }
public CipherString Value { get; set; }
}
}

View File

@@ -1,5 +1,6 @@
using Bit.App.Models.Api;
using Bit.App.Models.Data;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
@@ -26,24 +27,16 @@ namespace Bit.App.Models
Edit = data.Edit;
OrganizationUseTotp = data.OrganizationUseTotp;
Attachments = attachments?.Select(a => new Attachment(a));
}
public Login(LoginResponse response)
{
Id = response.Id;
UserId = response.UserId;
OrganizationId = response.OrganizationId;
FolderId = response.FolderId;
Name = response.Name != null ? new CipherString(response.Name) : null;
Uri = response.Uri != null ? new CipherString(response.Uri) : null;
Username = response.Username != null ? new CipherString(response.Username) : null;
Password = response.Password != null ? new CipherString(response.Password) : null;
Notes = response.Notes != null ? new CipherString(response.Notes) : null;
Totp = response.Totp != null ? new CipherString(response.Totp) : null;
Favorite = response.Favorite;
Edit = response.Edit;
OrganizationUseTotp = response.OrganizationUseTotp;
Attachments = response.Attachments?.Select(a => new Attachment(a));
if(!string.IsNullOrWhiteSpace(data.Fields))
{
try
{
var fieldModels = JsonConvert.DeserializeObject<IEnumerable<FieldDataModel>>(data.Fields);
Fields = fieldModels?.Select(f => new Field(f));
}
catch(JsonSerializationException) { }
}
}
public string Id { get; set; }
@@ -56,19 +49,10 @@ namespace Bit.App.Models
public CipherString Password { get; set; }
public CipherString Notes { get; set; }
public CipherString Totp { get; set; }
public IEnumerable<Field> Fields { get; set; }
public bool Favorite { get; set; }
public bool Edit { get; set; }
public bool OrganizationUseTotp { get; set; }
public IEnumerable<Attachment> Attachments { get; set; }
public LoginRequest ToLoginRequest()
{
return new LoginRequest(this);
}
public LoginData ToLoginData(string userId)
{
return new LoginData(this, userId);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.ComponentModel;
using Bit.App.Resources;
using Xamarin.Forms;
using System.Collections.Generic;
using Bit.App.Enums;
namespace Bit.App.Models.Page
{
@@ -17,6 +18,7 @@ namespace Bit.App.Models.Page
private int _totpSec = 30;
private bool _revealPassword;
private List<Attachment> _attachments;
private List<Field> _fields;
public VaultViewLoginPageModel() { }
@@ -39,31 +41,9 @@ namespace Bit.App.Models.Page
_username = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Username)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowUsername)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(UsernameFontSize)));
}
}
public bool ShowUsername => !string.IsNullOrWhiteSpace(Username);
public double UsernameFontSize
{
get
{
if(Device.RuntimePlatform == Device.Android)
{
var length = Username?.Length ?? 0;
if(length > 35)
{
return Device.GetNamedSize(NamedSize.Micro, typeof(Label));
}
else if(length > 25)
{
return Device.GetNamedSize(NamedSize.Small, typeof(Label));
}
}
return Device.GetNamedSize(NamedSize.Medium, typeof(Label));
}
}
public string Password
{
@@ -74,31 +54,9 @@ namespace Bit.App.Models.Page
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Password)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(PasswordFontSize)));
}
}
public bool ShowPassword => !string.IsNullOrWhiteSpace(Password);
public double PasswordFontSize
{
get
{
if(Device.RuntimePlatform == Device.Android)
{
var length = Password?.Length ?? 0;
if(length > 25)
{
return Device.GetNamedSize(NamedSize.Micro, typeof(Label));
}
else if(length > 20)
{
return Device.GetNamedSize(NamedSize.Small, typeof(Label));
}
}
return Device.GetNamedSize(NamedSize.Medium, typeof(Label));
}
}
public string Uri
{
@@ -159,10 +117,10 @@ namespace Bit.App.Models.Page
return Uri;
}
DomainName domain;
if(DomainName.TryParse(uri.Host, out domain))
string domain;
if(DomainName.TryParseBaseDomain(uri.Host, out domain))
{
return domain.BaseDomain;
return domain;
}
return uri.Host;
@@ -188,12 +146,10 @@ namespace Bit.App.Models.Page
_revealPassword = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(RevealPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideText)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideImage)));
}
}
public string MaskedPassword => RevealPassword ? Password : Password == null ? null : new string('●', Password.Length);
public string ShowHideText => RevealPassword ? AppResources.Hide : AppResources.Show;
public ImageSource ShowHideImage => RevealPassword ? ImageSource.FromFile("eye_slash") : ImageSource.FromFile("eye");
public string TotpCode
@@ -233,6 +189,18 @@ namespace Bit.App.Models.Page
}
public bool ShowAttachments => (Attachments?.Count ?? 0) > 0;
public List<Field> Fields
{
get { return _fields; }
set
{
_fields = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Fields)));
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowFields)));
}
}
public bool ShowFields => (Fields?.Count ?? 0) > 0;
public void Update(Login login)
{
Name = login.Name?.Decrypt(login.OrganizationId);
@@ -261,6 +229,25 @@ namespace Bit.App.Models.Page
{
login.Attachments = null;
}
if(login.Fields != null)
{
var fields = new List<Field>();
foreach(var field in login.Fields)
{
fields.Add(new Field
{
Name = field.Name?.Decrypt(login.OrganizationId),
Value = field.Value?.Decrypt(login.OrganizationId),
Type = field.Type
});
}
Fields = fields;
}
else
{
login.Fields = null;
}
}
public class Attachment
@@ -271,5 +258,27 @@ namespace Bit.App.Models.Page
public long Size { get; set; }
public string Url { get; set; }
}
public class Field
{
private string _maskedValue;
public string Name { get; set; }
public string Value { get; set; }
public string MaskedValue
{
get
{
if(_maskedValue == null && Value != null)
{
_maskedValue = new string('●', Value.Length);
}
return _maskedValue;
}
}
public FieldType Type { get; set; }
public bool Revealed { get; set; }
}
}
}

View File

@@ -0,0 +1,239 @@
using System;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Resources;
using Xamarin.Forms;
using XLabs.Ioc;
using Acr.UserDialogs;
using System.Threading.Tasks;
namespace Bit.App.Pages
{
public class EnvironmentPage : ExtendedContentPage
{
private IAppSettingsService _appSettings;
private IUserDialogs _userDialogs;
private IGoogleAnalyticsService _googleAnalyticsService;
public EnvironmentPage()
: base(updateActivity: false)
{
_appSettings = Resolver.Resolve<IAppSettingsService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
public FormEntryCell BaseUrlCell { get; set; }
public FormEntryCell WebVaultUrlCell { get; set; }
public FormEntryCell ApiUrlCell { get; set; }
public FormEntryCell IdentityUrlCell { get; set; }
public StackLayout StackLayout { get; set; }
public Label SelfHostLabel { get; set; }
public Label CustomLabel { get; set; }
private void Init()
{
MessagingCenter.Send(Application.Current, "ShowStatusBar", true);
IdentityUrlCell = new FormEntryCell(AppResources.IdentityUrl, entryKeyboard: Keyboard.Url);
IdentityUrlCell.Entry.Text = _appSettings.IdentityUrl;
ApiUrlCell = new FormEntryCell(AppResources.ApiUrl, nextElement: IdentityUrlCell.Entry, entryKeyboard: Keyboard.Url);
ApiUrlCell.Entry.Text = _appSettings.ApiUrl;
WebVaultUrlCell = new FormEntryCell(AppResources.WebVaultUrl, nextElement: ApiUrlCell.Entry, entryKeyboard: Keyboard.Url);
WebVaultUrlCell.Entry.Text = _appSettings.WebVaultUrl;
BaseUrlCell = new FormEntryCell(AppResources.ServerUrl, nextElement: WebVaultUrlCell.Entry, entryKeyboard: Keyboard.Url);
BaseUrlCell.Entry.Text = _appSettings.BaseUrl;
var table = new FormTableView
{
Root = new TableRoot
{
new TableSection(AppResources.SelfHostedEnvironment)
{
BaseUrlCell
}
}
};
SelfHostLabel = new Label
{
Text = AppResources.SelfHostedEnvironmentFooter,
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"],
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
};
var table2 = new FormTableView
{
Root = new TableRoot
{
new TableSection(AppResources.CustomEnvironment)
{
WebVaultUrlCell,
ApiUrlCell,
IdentityUrlCell
}
}
};
CustomLabel = new Label
{
Text = AppResources.CustomEnvironmentFooter,
LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"],
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
};
StackLayout = new StackLayout
{
Children = { table, SelfHostLabel, table2, CustomLabel },
Spacing = 0
};
var scrollView = new ScrollView
{
Content = StackLayout
};
var toolbarItem = new ToolbarItem(AppResources.Save, null, async () => await SaveAsync(),
ToolbarItemOrder.Default, 0);
if(Device.RuntimePlatform == Device.iOS)
{
table.RowHeight = table2.RowHeight = -1;
table.EstimatedRowHeight = table2.EstimatedRowHeight = 70;
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close, () =>
{
MessagingCenter.Send(Application.Current, "ShowStatusBar", false);
}));
}
ToolbarItems.Add(toolbarItem);
Title = AppResources.Settings;
Content = scrollView;
}
protected override void OnAppearing()
{
base.OnAppearing();
MessagingCenter.Send(Application.Current, "ShowStatusBar", true);
BaseUrlCell.InitEvents();
IdentityUrlCell.InitEvents();
ApiUrlCell.InitEvents();
WebVaultUrlCell.InitEvents();
StackLayout.LayoutChanged += Layout_LayoutChanged;
BaseUrlCell.Entry.FocusWithDelay();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
BaseUrlCell.Dispose();
IdentityUrlCell.Dispose();
ApiUrlCell.Dispose();
WebVaultUrlCell.Dispose();
StackLayout.LayoutChanged -= Layout_LayoutChanged;
}
private void Layout_LayoutChanged(object sender, EventArgs e)
{
SelfHostLabel.WidthRequest = StackLayout.Bounds.Width - SelfHostLabel.Bounds.Left * 2;
CustomLabel.WidthRequest = StackLayout.Bounds.Width - CustomLabel.Bounds.Left * 2;
}
private async Task SaveAsync()
{
Uri result;
if(!string.IsNullOrWhiteSpace(BaseUrlCell.Entry.Text))
{
BaseUrlCell.Entry.Text = FixUrl(BaseUrlCell.Entry.Text);
if(!Uri.TryCreate(BaseUrlCell.Entry.Text, UriKind.Absolute, out result))
{
_userDialogs.Alert(string.Format(AppResources.FormattedIncorrectly, AppResources.ServerUrl));
return;
}
}
else
{
BaseUrlCell.Entry.Text = null;
}
if(!string.IsNullOrWhiteSpace(WebVaultUrlCell.Entry.Text))
{
WebVaultUrlCell.Entry.Text = FixUrl(WebVaultUrlCell.Entry.Text);
if(!Uri.TryCreate(WebVaultUrlCell.Entry.Text, UriKind.Absolute, out result))
{
_userDialogs.Alert(string.Format(AppResources.FormattedIncorrectly, AppResources.WebVaultUrl));
return;
}
}
else
{
WebVaultUrlCell.Entry.Text = null;
}
if(!string.IsNullOrWhiteSpace(ApiUrlCell.Entry.Text))
{
ApiUrlCell.Entry.Text = FixUrl(ApiUrlCell.Entry.Text);
if(!Uri.TryCreate(ApiUrlCell.Entry.Text, UriKind.Absolute, out result))
{
_userDialogs.Alert(string.Format(AppResources.FormattedIncorrectly, AppResources.ApiUrl));
return;
}
}
else
{
ApiUrlCell.Entry.Text = null;
}
if(!string.IsNullOrWhiteSpace(IdentityUrlCell.Entry.Text))
{
IdentityUrlCell.Entry.Text = FixUrl(IdentityUrlCell.Entry.Text);
if(!Uri.TryCreate(IdentityUrlCell.Entry.Text, UriKind.Absolute, out result))
{
_userDialogs.Alert(string.Format(AppResources.FormattedIncorrectly, AppResources.IdentityUrl));
return;
}
}
else
{
IdentityUrlCell.Entry.Text = null;
}
_appSettings.BaseUrl = BaseUrlCell.Entry.Text;
_appSettings.IdentityUrl = IdentityUrlCell.Entry.Text;
_appSettings.ApiUrl = ApiUrlCell.Entry.Text;
_appSettings.WebVaultUrl = WebVaultUrlCell.Entry.Text;
_userDialogs.Toast(AppResources.EnvironmentSaved);
_googleAnalyticsService.TrackAppEvent("SetEnvironmentUrls");
await Navigation.PopForDeviceAsync();
}
private string FixUrl(string url)
{
url = url.TrimEnd('/');
if(!url.StartsWith("http://") && !url.StartsWith("https://"))
{
url = $"https://{url}";
}
return url;
}
private class FormTableView : ExtendedTableView
{
public FormTableView()
{
Intent = TableIntent.Settings;
EnableScrolling = false;
HasUnevenRows = true;
EnableSelection = true;
VerticalOptions = LayoutOptions.Start;
NoFooter = true;
}
}
}
}

View File

@@ -32,12 +32,25 @@ namespace Bit.App.Pages
{
MessagingCenter.Send(Application.Current, "ShowStatusBar", false);
var settingsButton = new Button
{
Image = "cog",
VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.Start,
WidthRequest = 25,
HeightRequest = 25,
BackgroundColor = Color.Transparent,
Margin = new Thickness(-20, -30, 0, 0),
Command = new Command(async () => await SettingsAsync())
};
var logo = new CachedImage
{
Source = "logo",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 282,
Margin = new Thickness(0, 30, 0, 0),
HeightRequest = 44
};
@@ -77,7 +90,7 @@ namespace Bit.App.Pages
{
Padding = new Thickness(30, 40),
Spacing = 10,
Children = { logo, message, createAccountButton, loginButton }
Children = { settingsButton, logo, message, createAccountButton, loginButton }
};
Title = AppResources.Bitwarden;
@@ -119,5 +132,16 @@ namespace Bit.App.Pages
await Navigation.PushForDeviceAsync(new LoginPage(email));
_userDialogs.Toast(AppResources.AccountCreated);
}
public async Task SettingsAsync()
{
if(_lastAction.LastActionWasRecent())
{
return;
}
_lastAction = DateTime.UtcNow;
await Navigation.PushForDeviceAsync(new EnvironmentPage());
}
}
}

View File

@@ -100,8 +100,31 @@ namespace Bit.App.Pages
{
base.OnAppearing();
PasswordCell.InitEvents();
PasswordCell.Entry.FocusWithDelay();
PasswordCell.Entry.Completed += Entry_Completed;
if(Device.RuntimePlatform == Device.Android)
{
Task.Run(async () =>
{
for(int i = 0; i < 5; i++)
{
if(!PasswordCell.Entry.IsFocused)
{
Device.BeginInvokeOnMainThread(() => PasswordCell.Entry.FocusWithDelay());
}
else
{
break;
}
await Task.Delay(1000);
}
});
}
else
{
PasswordCell.Entry.Focus();
}
}
protected override void OnDisappearing()

View File

@@ -5,6 +5,7 @@ using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Models.Page;
using Bit.App.Controls;
using System.Threading.Tasks;
namespace Bit.App.Pages
{
@@ -79,7 +80,30 @@ namespace Bit.App.Pages
_tgr.Tapped += Tgr_Tapped;
PinControl.OnPinEntered += PinEntered;
PinControl.InitEvents();
PinControl.Entry.FocusWithDelay();
if(Device.RuntimePlatform == Device.Android)
{
Task.Run(async () =>
{
for(int i = 0; i < 5; i++)
{
if(!PinControl.Entry.IsFocused)
{
Device.BeginInvokeOnMainThread(() => PinControl.Entry.Focus());
}
else
{
break;
}
await Task.Delay(1000);
}
});
}
else
{
PinControl.Entry.Focus();
}
}
protected override void OnDisappearing()

View File

@@ -26,6 +26,7 @@ namespace Bit.App.Pages
private IGoogleAnalyticsService _googleAnalyticsService;
private ITwoFactorApiRepository _twoFactorApiRepository;
private IPushNotification _pushNotification;
private IAppSettingsService _appSettingsService;
private readonly string _email;
private readonly string _masterPasswordHash;
private readonly SymmetricCryptoKey _key;
@@ -48,6 +49,7 @@ namespace Bit.App.Pages
_authService = Resolver.Resolve<IAuthService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_syncService = Resolver.Resolve<ISyncService>();
_appSettingsService = Resolver.Resolve<IAppSettingsService>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_twoFactorApiRepository = Resolver.Resolve<ITwoFactorApiRepository>();
_pushNotification = Resolver.Resolve<IPushNotification>();
@@ -185,9 +187,19 @@ namespace Bit.App.Pages
var host = WebUtility.UrlEncode(duoParams["Host"].ToString());
var req = WebUtility.UrlEncode(duoParams["Signature"].ToString());
var webVaultUrl = "https://vault.bitwarden.com";
if(!string.IsNullOrWhiteSpace(_appSettingsService.BaseUrl))
{
webVaultUrl = _appSettingsService.BaseUrl;
}
else if(!string.IsNullOrWhiteSpace(_appSettingsService.WebVaultUrl))
{
webVaultUrl = _appSettingsService.WebVaultUrl;
}
var webView = new HybridWebView
{
Uri = $"https://vault.bitwarden.com/duo-connector.html?host={host}&request={req}",
Uri = $"{webVaultUrl}/duo-connector.html?host={host}&request={req}",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
MinimumHeightRequest = 400

View File

@@ -7,7 +7,7 @@ namespace Bit.App.Pages
{
public class MainPage : ExtendedTabbedPage
{
public MainPage(string uri = null)
public MainPage(string uri = null, bool myVault = false)
{
TintColor = Color.FromHex("3c8dbc");
@@ -32,6 +32,11 @@ namespace Bit.App.Pages
Children.Add(vaultNavigation);
Children.Add(toolsNavigation);
Children.Add(settingsNavigation);
if(myVault || uri != null)
{
SelectedItem = vaultNavigation;
}
}
}
}

View File

@@ -20,6 +20,7 @@ namespace Bit.App.Pages
private readonly IFingerprint _fingerprint;
private readonly IPushNotification _pushNotification;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly IDeviceInfoService _deviceInfoService;
// TODO: Model binding context?
@@ -31,6 +32,7 @@ namespace Bit.App.Pages
_fingerprint = Resolver.Resolve<IFingerprint>();
_pushNotification = Resolver.Resolve<IPushNotification>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
Init();
}
@@ -213,7 +215,7 @@ namespace Bit.App.Pages
SyncCell.Tapped += SyncCell_Tapped;
LockCell.Tapped += LockCell_Tapped;
LogOutCell.Tapped += LogOutCell_Tapped;
AboutCell.Tapped += AboutCell_Tapped;
AboutCell.Tapped += AboutCell_Tapped;
HelpCell.Tapped += HelpCell_Tapped;
FeaturesCell.Tapped += FeaturesCell_Tapped;
@@ -328,8 +330,15 @@ namespace Bit.App.Pages
_googleAnalyticsService.TrackAppEvent("OpenedSetting", "RateApp");
if(Device.RuntimePlatform == Device.iOS)
{
Device.OpenUri(new Uri($"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews" +
"?id=1137397744&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"));
if(_deviceInfoService.Version < 11)
{
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews" +
"?id=1137397744&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"));
}
else
{
Device.OpenUri(new Uri("itms-apps://itunes.apple.com/us/app/id1137397744?action=write-review"));
}
}
else if(Device.RuntimePlatform == Device.Android)
{

View File

@@ -77,7 +77,11 @@ namespace Bit.App.Pages
private void SetLastSync()
{
var lastSyncDate = _settings.GetValueOrDefault<DateTime?>(Constants.LastSync, null);
DateTime? lastSyncDate = null;
if(_settings.Contains(Constants.LastSync))
{
lastSyncDate = _settings.GetValueOrDefault(Constants.LastSync, DateTime.UtcNow);
}
try
{
LastSyncLabel.Text = AppResources.LastSync + " " + lastSyncDate?.ToLocalTime().ToString() ?? AppResources.Never;

View File

@@ -49,7 +49,7 @@ namespace Bit.App.Pages
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
Margin = new Thickness(15, 40, 15, 40),
HorizontalTextAlignment = TextAlignment.Center,
FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier"),
FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier"),
LineBreakMode = LineBreakMode.TailTruncation,
VerticalOptions = LayoutOptions.Start
};

View File

@@ -25,6 +25,7 @@ namespace Bit.App.Pages
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly ISettings _settings;
private readonly IAppInfoService _appInfoService;
private readonly IDeviceInfoService _deviceInfo;
private readonly string _defaultUri;
private readonly string _defaultName;
private readonly bool _fromAutofill;
@@ -43,6 +44,7 @@ namespace Bit.App.Pages
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
_settings = Resolver.Resolve<ISettings>();
_appInfoService = Resolver.Resolve<IAppInfoService>();
_deviceInfo = Resolver.Resolve<IDeviceInfoService>();
Init();
}
@@ -59,20 +61,24 @@ namespace Bit.App.Pages
private void Init()
{
NotesCell = new FormEditorCell(height: 180);
NotesCell.Editor.Keyboard = Keyboard.Text;
TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor,
useButton: true);
TotpCell.Button.Image = "camera";
useButton: _deviceInfo.HasCamera);
if(_deviceInfo.HasCamera)
{
TotpCell.Button.Image = "camera";
}
TotpCell.Entry.DisableAutocapitalize = true;
TotpCell.Entry.Autocorrect = false;
TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier");
TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
PasswordCell = new FormEntryCell(AppResources.Password, isPassword: true, nextElement: TotpCell.Entry,
useButton: true);
PasswordCell.Button.Image = "eye";
PasswordCell.Entry.DisableAutocapitalize = true;
PasswordCell.Entry.Autocorrect = false;
PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier");
PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
UsernameCell = new FormEntryCell(AppResources.Username, nextElement: PasswordCell.Entry);
UsernameCell.Entry.DisableAutocapitalize = true;
@@ -142,7 +148,12 @@ namespace Bit.App.Pages
}
else if(Device.RuntimePlatform == Device.Android)
{
PasswordCell.Button.WidthRequest = TotpCell.Button.WidthRequest = 40;
PasswordCell.Button.WidthRequest = 40;
if(TotpCell.Button != null)
{
TotpCell.Button.WidthRequest = 40;
}
}
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
@@ -234,7 +245,10 @@ namespace Bit.App.Pages
TotpCell.InitEvents();
FolderCell.InitEvents();
PasswordCell.Button.Clicked += PasswordButton_Clicked;
TotpCell.Button.Clicked += TotpButton_Clicked;
if(TotpCell?.Button != null)
{
TotpCell.Button.Clicked += TotpButton_Clicked;
}
GenerateCell.Tapped += GenerateCell_Tapped;
if(!_fromAutofill && !_settings.GetValueOrDefault(AddedLoginAlertKey, false))
@@ -266,7 +280,10 @@ namespace Bit.App.Pages
TotpCell.Dispose();
FolderCell.Dispose();
PasswordCell.Button.Clicked -= PasswordButton_Clicked;
TotpCell.Button.Clicked -= TotpButton_Clicked;
if(TotpCell?.Button != null)
{
TotpCell.Button.Clicked -= TotpButton_Clicked;
}
GenerateCell.Tapped -= GenerateCell_Tapped;
}

View File

@@ -30,20 +30,15 @@ namespace Bit.App.Pages
Uri = uriString;
Uri uri;
DomainName domainName;
if(uriString?.StartsWith(Constants.AndroidAppProtocol) ?? false)
{
_name = uriString.Substring(Constants.AndroidAppProtocol.Length);
}
else if(!System.Uri.TryCreate(uriString, UriKind.Absolute, out uri) ||
!DomainName.TryParse(uri.Host, out domainName))
!DomainName.TryParseBaseDomain(uri.Host, out _name))
{
_name = "--";
}
else
{
_name = domainName.BaseDomain;
}
_loginService = Resolver.Resolve<ILoginService>();
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
@@ -210,7 +205,7 @@ namespace Bit.App.Pages
return;
}
if(Uri.StartsWith("http") && _deviceInfoService.Version < 21)
if(_deviceInfoService.Version < 21)
{
MoreClickedAsync(login);
}

View File

@@ -0,0 +1,248 @@
using System;
using System.Linq;
using Acr.UserDialogs;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Resources;
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Utilities;
using Plugin.Connectivity.Abstractions;
using Bit.App.Models;
using Bit.App.Enums;
using System.Collections.Generic;
namespace Bit.App.Pages
{
public class VaultCustomFieldsPage : ExtendedContentPage
{
private readonly ILoginService _loginService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private readonly string _loginId;
private Login _login;
private DateTime? _lastAction;
public VaultCustomFieldsPage(string loginId)
: base(true)
{
_loginId = loginId;
_loginService = Resolver.Resolve<ILoginService>();
_connectivity = Resolver.Resolve<IConnectivity>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
}
public ToolbarItem SaveToolbarItem { get; set; }
public Label NoDataLabel { get; set; }
public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; }
private void Init()
{
FieldsSection = new TableSection(" ");
Table = new ExtendedTableView
{
Intent = TableIntent.Settings,
EnableScrolling = true,
HasUnevenRows = true,
Root = new TableRoot
{
FieldsSection
}
};
NoDataLabel = new Label
{
Text = AppResources.NoCustomFields,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)),
Margin = new Thickness(10, 40, 10, 0)
};
SaveToolbarItem = new ToolbarItem(AppResources.Save, null, async () =>
{
if(_lastAction.LastActionWasRecent() || _login == null)
{
return;
}
_lastAction = DateTime.UtcNow;
if(!_connectivity.IsConnected)
{
AlertNoConnection();
return;
}
if(FieldsSection.Count > 0)
{
var fields = new List<Field>();
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entryCell)
{
fields.Add(new Field
{
Name = string.IsNullOrWhiteSpace(entryCell.Label.Text) ? null :
entryCell.Label.Text.Encrypt(_login.OrganizationId),
Value = string.IsNullOrWhiteSpace(entryCell.Entry.Text) ? null :
entryCell.Entry.Text.Encrypt(_login.OrganizationId),
Type = entryCell.Entry.IsPassword ? FieldType.Hidden : FieldType.Text
});
}
else if(cell is ExtendedSwitchCell switchCell)
{
var value = switchCell.On ? "true" : "false";
fields.Add(new Field
{
Name = string.IsNullOrWhiteSpace(switchCell.Text) ? null :
switchCell.Text.Encrypt(_login.OrganizationId),
Value = value.Encrypt(_login.OrganizationId),
Type = FieldType.Boolean
});
}
}
_login.Fields = fields;
}
else
{
_login.Fields = null;
}
_userDialogs.ShowLoading(AppResources.Saving, MaskType.Black);
var saveTask = await _loginService.SaveAsync(_login);
_userDialogs.HideLoading();
if(saveTask.Succeeded)
{
_userDialogs.Toast(AppResources.CustomFieldsUpdated);
_googleAnalyticsService.TrackAppEvent("UpdatedCustomFields");
await Navigation.PopForDeviceAsync();
}
else if(saveTask.Errors.Count() > 0)
{
await _userDialogs.AlertAsync(saveTask.Errors.First().Message, AppResources.AnErrorHasOccurred);
}
else
{
await _userDialogs.AlertAsync(AppResources.AnErrorHasOccurred);
}
}, ToolbarItemOrder.Default, 0);
Title = AppResources.CustomFields;
Content = Table;
if(Device.RuntimePlatform == Device.iOS)
{
Table.RowHeight = -1;
Table.EstimatedRowHeight = 44;
}
}
protected async override void OnAppearing()
{
base.OnAppearing();
_login = await _loginService.GetByIdAsync(_loginId);
if(_login == null)
{
await Navigation.PopForDeviceAsync();
return;
}
if(_login.Fields != null && _login.Fields.Any())
{
Content = Table;
ToolbarItems.Add(SaveToolbarItem);
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Cancel));
}
foreach(var field in _login.Fields)
{
var label = field.Name?.Decrypt(_login.OrganizationId) ?? string.Empty;
var value = field.Value?.Decrypt(_login.OrganizationId);
switch(field.Type)
{
case FieldType.Text:
case FieldType.Hidden:
var hidden = field.Type == FieldType.Hidden;
var textFieldCell = new FormEntryCell(label, isPassword: hidden, useButton: hidden);
textFieldCell.Entry.Text = value;
textFieldCell.Entry.DisableAutocapitalize = true;
textFieldCell.Entry.Autocorrect = false;
if(hidden)
{
textFieldCell.Entry.FontFamily = Helpers.OnPlatform(
iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
textFieldCell.Button.Image = "eye";
textFieldCell.Button.Command = new Command(() =>
{
textFieldCell.Entry.InvokeToggleIsPassword();
textFieldCell.Button.Image =
"eye" + (!textFieldCell.Entry.IsPasswordFromToggled ? "_slash" : string.Empty);
});
}
if(Device.RuntimePlatform == Device.Android && textFieldCell.Button != null)
{
textFieldCell.Button.WidthRequest = 40;
}
textFieldCell.InitEvents();
FieldsSection.Add(textFieldCell);
break;
case FieldType.Boolean:
var switchFieldCell = new ExtendedSwitchCell
{
Text = label,
On = value == "true"
};
FieldsSection.Add(switchFieldCell);
break;
default:
continue;
}
}
}
else
{
Content = NoDataLabel;
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close));
}
}
}
protected override void OnDisappearing()
{
base.OnDisappearing();
if(FieldsSection != null && FieldsSection.Count > 0)
{
foreach(var cell in FieldsSection)
{
if(cell is FormEntryCell entrycell)
{
entrycell.Dispose();
}
}
}
}
private void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage,
AppResources.Ok);
}
}
}

View File

@@ -19,6 +19,7 @@ namespace Bit.App.Pages
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
private readonly IDeviceInfoService _deviceInfo;
private readonly IGoogleAnalyticsService _googleAnalyticsService;
private DateTime? _lastAction;
@@ -29,6 +30,7 @@ namespace Bit.App.Pages
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
_deviceInfo = Resolver.Resolve<IDeviceInfoService>();
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
Init();
@@ -43,6 +45,7 @@ namespace Bit.App.Pages
public FormPickerCell FolderCell { get; private set; }
public ExtendedTextCell GenerateCell { get; private set; }
public ExtendedTextCell AttachmentsCell { get; private set; }
public ExtendedTextCell CustomFieldsCell { get; private set; }
public ExtendedTextCell DeleteCell { get; private set; }
private void Init()
@@ -54,16 +57,20 @@ namespace Bit.App.Pages
return;
}
NotesCell = new FormEditorCell(height: 180);
NotesCell = new FormEditorCell(height: 300);
NotesCell.Editor.Keyboard = Keyboard.Text;
NotesCell.Editor.Text = login.Notes?.Decrypt(login.OrganizationId);
TotpCell = new FormEntryCell(AppResources.AuthenticatorKey, nextElement: NotesCell.Editor,
useButton: true);
useButton: _deviceInfo.HasCamera);
if(_deviceInfo.HasCamera)
{
TotpCell.Button.Image = "camera";
}
TotpCell.Entry.Text = login.Totp?.Decrypt(login.OrganizationId);
TotpCell.Button.Image = "camera";
TotpCell.Entry.DisableAutocapitalize = true;
TotpCell.Entry.Autocorrect = false;
TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier");
TotpCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
PasswordCell = new FormEntryCell(AppResources.Password, isPassword: true, nextElement: TotpCell.Entry,
useButton: true);
@@ -71,7 +78,7 @@ namespace Bit.App.Pages
PasswordCell.Button.Image = "eye";
PasswordCell.Entry.DisableAutocapitalize = true;
PasswordCell.Entry.Autocorrect = false;
PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier");
PasswordCell.Entry.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
UsernameCell = new FormEntryCell(AppResources.Username, nextElement: PasswordCell.Entry);
UsernameCell.Entry.Text = login.Username?.Decrypt(login.OrganizationId);
@@ -119,6 +126,12 @@ namespace Bit.App.Pages
ShowDisclousure = true
};
CustomFieldsCell = new ExtendedTextCell
{
Text = AppResources.CustomFields,
ShowDisclousure = true
};
DeleteCell = new ExtendedTextCell { Text = AppResources.Delete, TextColor = Color.Red };
var table = new ExtendedTableView
@@ -141,7 +154,8 @@ namespace Bit.App.Pages
TotpCell,
FolderCell,
favoriteCell,
AttachmentsCell
AttachmentsCell,
CustomFieldsCell
},
new TableSection(AppResources.Notes)
{
@@ -161,7 +175,12 @@ namespace Bit.App.Pages
}
else if(Device.RuntimePlatform == Device.Android)
{
PasswordCell.Button.WidthRequest = TotpCell.Button.WidthRequest = 40;
PasswordCell.Button.WidthRequest = 40;
if(TotpCell.Button != null)
{
TotpCell.Button.WidthRequest = 40;
}
}
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
@@ -215,7 +234,7 @@ namespace Bit.App.Pages
if(saveTask.Succeeded)
{
_userDialogs.Toast(AppResources.LoginUpdated);
_googleAnalyticsService.TrackAppEvent("EditeLogin");
_googleAnalyticsService.TrackAppEvent("EditedLogin");
await Navigation.PopForDeviceAsync();
}
else if(saveTask.Errors.Count() > 0)
@@ -269,6 +288,10 @@ namespace Bit.App.Pages
{
AttachmentsCell.Tapped += AttachmentsCell_Tapped;
}
if(CustomFieldsCell != null)
{
CustomFieldsCell.Tapped += CustomFieldsCell_Tapped;
}
if(DeleteCell != null)
{
DeleteCell.Tapped += DeleteCell_Tapped;
@@ -302,6 +325,10 @@ namespace Bit.App.Pages
{
AttachmentsCell.Tapped -= AttachmentsCell_Tapped;
}
if(CustomFieldsCell != null)
{
CustomFieldsCell.Tapped -= CustomFieldsCell_Tapped;
}
if(DeleteCell != null)
{
DeleteCell.Tapped -= DeleteCell_Tapped;
@@ -358,6 +385,12 @@ namespace Bit.App.Pages
await Navigation.PushModalAsync(page);
}
private async void CustomFieldsCell_Tapped(object sender, EventArgs e)
{
var page = new ExtendedNavigationPage(new VaultCustomFieldsPage(_loginId));
await Navigation.PushModalAsync(page);
}
private async void DeleteCell_Tapped(object sender, EventArgs e)
{
if(!_connectivity.IsConnected)

View File

@@ -239,9 +239,8 @@ namespace Bit.App.Pages
var pushPromptShow = _settings.GetValueOrDefault(Constants.PushInitialPromptShown, false);
Action registerAction = () =>
{
var lastPushRegistration = _settings.GetValueOrDefault<DateTime?>(Constants.PushLastRegistrationDate, null);
if(!pushPromptShow || !lastPushRegistration.HasValue
|| (DateTime.UtcNow - lastPushRegistration) > TimeSpan.FromDays(1))
var lastPushRegistration = _settings.GetValueOrDefault(Constants.PushLastRegistrationDate, DateTime.MinValue);
if(!pushPromptShow || DateTime.UtcNow - lastPushRegistration > TimeSpan.FromDays(1))
{
_pushNotification.Register();
}
@@ -404,7 +403,7 @@ namespace Bit.App.Pages
}
else if(selection == AppResources.Autofill)
{
if(Uri.StartsWith("http") && _deviceInfoService.Version < 21)
if(_deviceInfoService.Version < 21)
{
MoreClickedAsync(login);
}

View File

@@ -11,6 +11,7 @@ using Bit.App.Utilities;
using System.Collections.Generic;
using Bit.App.Models;
using System.Linq;
using Bit.App.Enums;
namespace Bit.App.Pages
{
@@ -39,12 +40,14 @@ namespace Bit.App.Pages
private TableSection LoginInformationSection { get; set; }
private TableSection NotesSection { get; set; }
private TableSection AttachmentsSection { get; set; }
private TableSection FieldsSection { get; set; }
public LabeledValueCell UsernameCell { get; set; }
public LabeledValueCell PasswordCell { get; set; }
public LabeledValueCell UriCell { get; set; }
public LabeledValueCell NotesCell { get; set; }
public LabeledValueCell TotpCodeCell { get; set; }
private EditLoginToolBarItem EditItem { get; set; }
public List<LabeledValueCell> FieldsCells { get; set; }
public List<AttachmentViewCell> AttachmentCells { get; set; }
private void Init()
@@ -63,14 +66,13 @@ namespace Bit.App.Pages
// Username
UsernameCell = new LabeledValueCell(AppResources.Username, button1Text: AppResources.Copy);
UsernameCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewLoginPageModel.Username));
UsernameCell.Value.SetBinding(Label.FontSizeProperty, nameof(VaultViewLoginPageModel.UsernameFontSize));
UsernameCell.Button1.Command = new Command(() => Copy(Model.Username, AppResources.Username));
UsernameCell.Value.LineBreakMode = LineBreakMode.WordWrap;
// Password
PasswordCell = new LabeledValueCell(AppResources.Password, button1Text: string.Empty,
button2Text: AppResources.Copy);
PasswordCell.Value.SetBinding(Label.TextProperty, nameof(VaultViewLoginPageModel.MaskedPassword));
PasswordCell.Value.SetBinding(Label.FontSizeProperty, nameof(VaultViewLoginPageModel.PasswordFontSize));
PasswordCell.Button1.SetBinding(Button.ImageProperty, nameof(VaultViewLoginPageModel.ShowHideImage));
if(Device.RuntimePlatform == Device.iOS)
{
@@ -78,7 +80,8 @@ namespace Bit.App.Pages
}
PasswordCell.Button1.Command = new Command(() => Model.RevealPassword = !Model.RevealPassword);
PasswordCell.Button2.Command = new Command(() => Copy(Model.Password, AppResources.Password));
PasswordCell.Value.FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier");
PasswordCell.Value.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
PasswordCell.Value.LineBreakMode = LineBreakMode.WordWrap;
// URI
UriCell = new LabeledValueCell(AppResources.Website, button1Text: AppResources.Launch);
@@ -103,7 +106,7 @@ namespace Bit.App.Pages
TotpCodeCell.Button1.Command = new Command(() => Copy(Model.TotpCode, AppResources.VerificationCodeTotp));
TotpCodeCell.Sub.SetBinding(Label.TextProperty, nameof(VaultViewLoginPageModel.TotpSecond));
TotpCodeCell.Sub.SetBinding(Label.TextColorProperty, nameof(VaultViewLoginPageModel.TotpColor));
TotpCodeCell.Value.FontFamily = Helpers.OnPlatform(iOS: "Courier", Android: "monospace", WinPhone: "Courier");
TotpCodeCell.Value.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular", Android: "monospace", WinPhone: "Courier");
// Notes
NotesCell = new LabeledValueCell();
@@ -255,6 +258,35 @@ namespace Bit.App.Pages
Table.Root.Add(AttachmentsSection);
}
if(Table.Root.Contains(FieldsSection))
{
Table.Root.Remove(FieldsSection);
}
if(Model.ShowFields)
{
FieldsSection = new TableSection(AppResources.CustomFields);
foreach(var field in Model.Fields)
{
FieldViewCell fieldCell;
switch(field.Type)
{
case FieldType.Text:
fieldCell = new FieldViewCell(this, field, null);
break;
case FieldType.Hidden:
fieldCell = new FieldViewCell(this, field, null, null);
break;
case FieldType.Boolean:
fieldCell = new FieldViewCell(this, field);
break;
default:
continue;
}
FieldsSection.Add(fieldCell);
}
Table.Root.Add(FieldsSection);
}
base.OnAppearing();
}
@@ -322,8 +354,8 @@ namespace Bit.App.Pages
private void Copy(string copyText, string alertLabel)
{
_deviceActionService.CopyToClipboard(copyText);
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
_deviceActionService.CopyToClipboard(copyText);
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
}
private void TotpTick(string totpKey)
@@ -387,5 +419,60 @@ namespace Bit.App.Pages
_tapped?.Invoke();
}
}
public class FieldViewCell : LabeledValueCell
{
public FieldViewCell(VaultViewLoginPage page, VaultViewLoginPageModel.Field field)
: base(field.Name, field.Value == "true" ? "✓" : "-")
{
Init(page, field, null);
}
public FieldViewCell(VaultViewLoginPage page, VaultViewLoginPageModel.Field field, bool? a)
: base(field.Name, field.Value, AppResources.Copy)
{
Init(page, field, Button1);
}
public FieldViewCell(VaultViewLoginPage page, VaultViewLoginPageModel.Field field, bool? a, bool? b)
: base(field.Name, field.MaskedValue, string.Empty, AppResources.Copy)
{
Value.FontFamily = Helpers.OnPlatform(iOS: "Menlo-Regular",
Android: "monospace", WinPhone: "Courier");
if(Device.RuntimePlatform == Device.iOS)
{
Button1.Margin = new Thickness(10, 0);
}
Button1.WidthRequest = 40;
Button1.Image = "eye";
Button1.Command = new Command(() =>
{
field.Revealed = !field.Revealed;
if(field.Revealed)
{
Button1.Image = "eye_slash";
Value.Text = field.Value;
}
else
{
Button1.Image = "eye";
Value.Text = field.MaskedValue;
}
});
Init(page, field, Button2);
}
private void Init(VaultViewLoginPage page, VaultViewLoginPageModel.Field field, ExtendedButton copyButton)
{
Value.LineBreakMode = LineBreakMode.WordWrap;
if(copyButton != null)
{
copyButton.Command = new Command(() => page.Copy(field.Value, field.Name));
copyButton.WidthRequest = 59;
}
}
}
}
}

View File

@@ -32,7 +32,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage(requestObj)
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/register")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/register")),
};
try
@@ -64,7 +64,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage(requestObj)
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/password-hint")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/password-hint")),
};
try
@@ -102,7 +102,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/revision-date")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/revision-date")),
};
try
@@ -151,7 +151,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/profile")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/profile")),
};
try
@@ -172,45 +172,5 @@ namespace Bit.App.Repositories
}
}
}
public virtual async Task<ApiResult<KeysResponse>> GetKeys()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<KeysResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<KeysResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/keys")),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<KeysResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<KeysResponse>(responseContent);
return ApiResult<KeysResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<KeysResponse>();
}
}
}
}
}

View File

@@ -6,7 +6,6 @@ using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using Plugin.Connectivity.Abstractions;
using System.Net;
namespace Bit.App.Repositories
{
@@ -40,7 +39,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/", id)),
};
try
@@ -80,7 +79,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress, ApiRoute),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute)),
};
try
@@ -120,7 +119,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage(requestObj)
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, ApiRoute),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute)),
};
try
@@ -160,7 +159,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage(requestObj)
{
Method = HttpMethod.Put,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/", id)),
};
try
@@ -200,7 +199,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Delete,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/", id)),
};
try

View File

@@ -7,7 +7,6 @@ using Newtonsoft.Json;
using Plugin.Connectivity.Abstractions;
using Bit.App.Abstractions;
using System.Net;
using XLabs.Ioc;
using Newtonsoft.Json.Linq;
namespace Bit.App.Repositories
@@ -48,61 +47,14 @@ namespace Bit.App.Repositories
private async Task<T> HandleTokenStateAsync<T>(Func<T> success, Func<T> webException,
Func<HttpResponseMessage, Task<T>> error)
{
if(!string.IsNullOrWhiteSpace(TokenService.AuthBearer) && string.IsNullOrWhiteSpace(TokenService.Token))
{
// Migrate from old auth bearer to new access token
var deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
var appIdService = Resolver.Resolve<IAppIdService>();
using(var client = HttpService.IdentityClient)
{
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, "connect/token"),
Content = new FormUrlEncodedContent(new TokenRequest
{
Email = "abcdefgh",
MasterPasswordHash = "abcdefgh",
OldAuthBearer = TokenService.AuthBearer,
Device = new DeviceRequest(appIdService, deviceInfoService)
}.ToIdentityTokenRequest())
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
if(response.StatusCode == HttpStatusCode.BadRequest)
{
response.StatusCode = HttpStatusCode.Unauthorized;
}
return await error.Invoke(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var tokenResponse = JsonConvert.DeserializeObject<TokenResponse>(responseContent);
TokenService.Token = tokenResponse.AccessToken;
TokenService.RefreshToken = tokenResponse.RefreshToken;
TokenService.AuthBearer = null;
}
catch
{
return webException.Invoke();
}
}
}
else if(TokenService.TokenNeedsRefresh && !string.IsNullOrWhiteSpace(TokenService.RefreshToken))
if(TokenService.TokenNeedsRefresh && !string.IsNullOrWhiteSpace(TokenService.RefreshToken))
{
using(var client = HttpService.IdentityClient)
{
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, "connect/token"),
RequestUri = new Uri(string.Concat(client.BaseAddress, "/connect/token")),
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "refresh_token" },
@@ -135,10 +87,6 @@ namespace Bit.App.Repositories
}
}
}
else if(!string.IsNullOrWhiteSpace(TokenService.AuthBearer))
{
TokenService.AuthBearer = null;
}
return success.Invoke();
}
@@ -178,7 +126,7 @@ namespace Bit.App.Repositories
{ }
return ApiResult<T>.Failed(response.StatusCode,
new ApiError { Message = "An unknown error has occured." });
new ApiError { Message = "An unknown error has occurred." });
}
protected async Task<ApiResult> HandleErrorAsync(HttpResponseMessage response)
@@ -192,7 +140,7 @@ namespace Bit.App.Repositories
{ }
return ApiResult.Failed(response.StatusCode,
new ApiError { Message = "An unknown error has occured." });
new ApiError { Message = "An unknown error has occurred." });
}
private async Task<List<ApiError>> ParseErrorsAsync(HttpResponseMessage response)
@@ -238,7 +186,7 @@ namespace Bit.App.Repositories
if(errors.Count == 0)
{
errors.Add(new ApiError { Message = "An unknown error has occured." });
errors.Add(new ApiError { Message = "An unknown error has occurred." });
}
return errors;

View File

@@ -5,12 +5,11 @@ using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Newtonsoft.Json;
using Plugin.Connectivity.Abstractions;
using System.Globalization;
using System.IO;
namespace Bit.App.Repositories
{
public class CipherApiRepository : BaseApiRepository, ICipherApiRepository
public class CipherApiRepository : ApiRepository<CipherRequest, CipherResponse, string>, ICipherApiRepository
{
public CipherApiRepository(
IConnectivity connectivity,
@@ -21,87 +20,6 @@ namespace Bit.App.Repositories
protected override string ApiRoute => "ciphers";
public virtual async Task<ApiResult<CipherResponse>> GetByIdAsync(string id)
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<CipherResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<CipherResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", id)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<CipherResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<CipherResponse>(responseContent);
return ApiResult<CipherResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<CipherResponse>();
}
}
}
public virtual async Task<ApiResult<ListResponse<CipherResponse>>> GetAsync()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<ListResponse<CipherResponse>>();
}
var tokenStateResponse = await HandleTokenStateAsync<ListResponse<CipherResponse>>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress,
string.Format("{0}?includeFolders=false&includeShared=true", ApiRoute)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<ListResponse<CipherResponse>>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<ListResponse<CipherResponse>>(responseContent);
return ApiResult<ListResponse<CipherResponse>>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<ListResponse<CipherResponse>>();
}
}
}
public virtual async Task<ApiResult<CipherResponse>> PostAttachmentAsync(string cipherId, byte[] data,
string fileName)
{
@@ -124,7 +42,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/", cipherId, "/attachment")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/", cipherId, "/attachment")),
Content = content
};
@@ -165,8 +83,8 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Delete,
RequestUri = new Uri(client.BaseAddress,
string.Concat(ApiRoute, "/", cipherId, "/attachment/", attachmentId)),
RequestUri = new Uri(
string.Concat(client.BaseAddress, ApiRoute, "/", cipherId, "/attachment/", attachmentId)),
};
try

View File

@@ -34,7 +34,7 @@ namespace Bit.App.Repositories
var requestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/token")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/token")),
Content = new FormUrlEncodedContent(requestObj.ToIdentityTokenRequest())
};

View File

@@ -38,7 +38,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage(request)
{
Method = HttpMethod.Put,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/identifier/", identifier, "/token")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/identifier/", identifier, "/token")),
};
try
@@ -70,8 +70,8 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage
{
Method = HttpMethod.Put,
RequestUri = new Uri(client.BaseAddress,
string.Concat(ApiRoute, "/identifier/", identifier, "/clear-token"))
RequestUri = new Uri(
string.Concat(client.BaseAddress, ApiRoute, "/identifier/", identifier, "/clear-token"))
};
try

View File

@@ -1,19 +0,0 @@
using System;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Plugin.Connectivity.Abstractions;
namespace Bit.App.Repositories
{
public class LoginApiRepository : ApiRepository<LoginRequest, LoginResponse, string>, ILoginApiRepository
{
public LoginApiRepository(
IConnectivity connectivity,
IHttpService httpService,
ITokenService tokenService)
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "sites";
}
}

View File

@@ -37,8 +37,8 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(client.BaseAddress,
string.Concat(ApiRoute, "/domains?excluded=", excluded.ToString().ToLowerInvariant())),
RequestUri = new Uri(
string.Concat(client.BaseAddress, ApiRoute, "/domains?excluded=", excluded.ToString().ToLowerInvariant())),
};
try

View File

@@ -0,0 +1,63 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Models.Api;
using Plugin.Connectivity.Abstractions;
using Newtonsoft.Json;
namespace Bit.App.Repositories
{
public class SyncApiRepository : BaseApiRepository, ISyncApiRepository
{
public SyncApiRepository(
IConnectivity connectivity,
IHttpService httpService,
ITokenService tokenService)
: base(connectivity, httpService, tokenService)
{ }
protected override string ApiRoute => "sync";
public virtual async Task<ApiResult<SyncResponse>> Get()
{
if(!Connectivity.IsConnected)
{
return HandledNotConnected<SyncResponse>();
}
var tokenStateResponse = await HandleTokenStateAsync<SyncResponse>();
if(!tokenStateResponse.Succeeded)
{
return tokenStateResponse;
}
using(var client = HttpService.ApiClient)
{
var requestMessage = new TokenHttpRequestMessage()
{
Method = HttpMethod.Get,
RequestUri = new Uri(
string.Concat(client.BaseAddress, ApiRoute)),
};
try
{
var response = await client.SendAsync(requestMessage).ConfigureAwait(false);
if(!response.IsSuccessStatusCode)
{
return await HandleErrorAsync<SyncResponse>(response).ConfigureAwait(false);
}
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObj = JsonConvert.DeserializeObject<SyncResponse>(responseContent);
return ApiResult<SyncResponse>.Success(responseObj, response.StatusCode);
}
catch
{
return HandledWebException<SyncResponse>();
}
}
}
}
}

View File

@@ -30,7 +30,7 @@ namespace Bit.App.Repositories
var requestMessage = new TokenHttpRequestMessage(requestObj)
{
Method = HttpMethod.Post,
RequestUri = new Uri(client.BaseAddress, string.Concat(ApiRoute, "/send-email-login")),
RequestUri = new Uri(string.Concat(client.BaseAddress, ApiRoute, "/send-email-login")),
};
try

View File

@@ -20,7 +20,7 @@ namespace Bit.App.Resources {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class AppResources {
@@ -142,6 +142,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to API Server URL.
/// </summary>
public static string ApiUrl {
get {
return ResourceManager.GetString("ApiUrl", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to App Extension.
/// </summary>
@@ -430,6 +439,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Tap this notification to view logins from your vault..
/// </summary>
public static string BitwardenAutofillServiceNotificationContentOld {
get {
return ResourceManager.GetString("BitwardenAutofillServiceNotificationContentOld", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open Accessibility Settings.
/// </summary>
@@ -682,6 +700,42 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Custom Environment.
/// </summary>
public static string CustomEnvironment {
get {
return ResourceManager.GetString("CustomEnvironment", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to For advanced users. You can specify the base URL of each service independently..
/// </summary>
public static string CustomEnvironmentFooter {
get {
return ResourceManager.GetString("CustomEnvironmentFooter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Custom Fields.
/// </summary>
public static string CustomFields {
get {
return ResourceManager.GetString("CustomFields", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Custom fields updated..
/// </summary>
public static string CustomFieldsUpdated {
get {
return ResourceManager.GetString("CustomFieldsUpdated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Delete.
/// </summary>
@@ -880,6 +934,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to The environment URLs have been saved..
/// </summary>
public static string EnvironmentSaved {
get {
return ResourceManager.GetString("EnvironmentSaved", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Re-enable App Extension.
/// </summary>
@@ -1132,6 +1195,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to {0} is not correctly formatted..
/// </summary>
public static string FormattedIncorrectly {
get {
return ResourceManager.GetString("FormattedIncorrectly", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Generate Password.
/// </summary>
@@ -1186,6 +1258,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Identity Server URL.
/// </summary>
public static string IdentityUrl {
get {
return ResourceManager.GetString("IdentityUrl", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Import Logins.
/// </summary>
@@ -1654,6 +1735,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to No custom fields. You can fully manage custom fields from the web vault or browser extension..
/// </summary>
public static string NoCustomFields {
get {
return ResourceManager.GetString("NoCustomFields", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to There are no favorites in your vault..
/// </summary>
@@ -2005,6 +2095,24 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Self-hosted Environment.
/// </summary>
public static string SelfHostedEnvironment {
get {
return ResourceManager.GetString("SelfHostedEnvironment", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Specify the base URL of your on-premise hosted bitwarden installation..
/// </summary>
public static string SelfHostedEnvironmentFooter {
get {
return ResourceManager.GetString("SelfHostedEnvironmentFooter", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Send verification code email again.
/// </summary>
@@ -2014,6 +2122,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Server URL.
/// </summary>
public static string ServerUrl {
get {
return ResourceManager.GetString("ServerUrl", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Set PIN.
/// </summary>
@@ -2446,6 +2563,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Web Vault Server URL.
/// </summary>
public static string WebVaultUrl {
get {
return ResourceManager.GetString("WebVaultUrl", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Yes.
/// </summary>

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -995,4 +995,48 @@
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -190,7 +190,7 @@
<comment>Full label for a email address.</comment>
</data>
<data name="EmailUs" xml:space="preserve">
<value>Écrivez-nous</value>
<value>Nous contacter</value>
</data>
<data name="EmailUsDescription" xml:space="preserve">
<value>Contactez-nous directement pour obtenir de l'aide ou pour nous faire part d'un commentaire.</value>
@@ -382,7 +382,7 @@
<value>Voir</value>
</data>
<data name="VisitOurWebsite" xml:space="preserve">
<value>Visitez notre site web</value>
<value>Visiter notre site web</value>
</data>
<data name="VisitOurWebsiteDescription" xml:space="preserve">
<value>Visitez notre site web pour obtenir de l'aide, lire les actualités, nous écrire et/ou apprendre à mieux utiliser bitwarden.</value>
@@ -723,7 +723,7 @@
<value>Déverrouiller avec un code PIN</value>
</data>
<data name="Validating" xml:space="preserve">
<value>Validating</value>
<value>Validation</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="VerificationCode" xml:space="preserve">
@@ -820,7 +820,7 @@
<value>Créez une organisation pour partager de manière sécurisée vos identifiants avec d\'autres utilisateurs.</value>
</data>
<data name="DisableGADescription" xml:space="preserve">
<value>We use analytics to better learn how the app is being used so that we can make it better. All data collection is completely anonymous.</value>
<value>Nous utilisons des statistiques pour mieux comprendre comment l'application est utilisée et ainsi l'améliorer. Toutes les données collectées sont entièrement anonymes.</value>
</data>
<data name="Features" xml:space="preserve">
<value>Fonctionnalités</value>
@@ -844,155 +844,199 @@
<value>Scanner en permanence l'écran à la recherche de champs et uniquement proposer la notification d'auto-complétion si des champs "Mot de passe" sont trouvés. Ceci est le paramètre par défaut.</value>
</data>
<data name="CannotOpenApp" xml:space="preserve">
<value>Cannot open the app "{0}".</value>
<value>Impossible d'ouvrir l'application "{0}".</value>
<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>Authenticator App</value>
<value>Application d'authentification</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeApp" xml:space="preserve">
<value>Enter the 6 digit verification code from your authenticator app.</value>
<value>Saisissez le code de vérification à 6 chiffres depuis votre application d'authentification.</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeEmail" xml:space="preserve">
<value>Enter the 6 digit verification code that was emailed to {0}.</value>
<value>Saisissez le code de vérification à 6 chiffres qui vous a été envoyé par e-mail à {0}.</value>
<comment>For 2FA</comment>
</data>
<data name="LoginUnavailable" xml:space="preserve">
<value>Login Unavailable</value>
<value>Identifiant non disponible</value>
<comment>For 2FA whenever there are no available providers on this device.</comment>
</data>
<data name="NoTwoStepAvailable" xml:space="preserve">
<value>This account has two-step login enabled, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app).</value>
<value>Ce compte utilise l'authentification à double facteurs, mais aucun des services d'authentification à double facteurs n'est supporté sur cet appareil. Veuillez utiliser un appareil compatible et/ou ajouter des services supplémentaires qui sont mieux supportés sur les appareils (comme une application d'authentification).</value>
</data>
<data name="RecoveryCodeTitle" xml:space="preserve">
<value>Recovery Code</value>
<value>Code de récupération</value>
<comment>For 2FA</comment>
</data>
<data name="RememberMe" xml:space="preserve">
<value>Remember me</value>
<value>Rester connecté</value>
<comment>Remember my two-step login</comment>
</data>
<data name="SendVerificationCodeAgain" xml:space="preserve">
<value>Send verification code email again</value>
<value>Envoyer à nouveau l'e-mail du code de vérification</value>
<comment>For 2FA</comment>
</data>
<data name="TwoStepLoginOptions" xml:space="preserve">
<value>Two-step Login Options</value>
<value>Options d'identification à double facteurs</value>
</data>
<data name="UseAnotherTwoStepMethod" xml:space="preserve">
<value>Use another two-step login method</value>
<value>Utiliser une autre méthode d'identification à double facteurs</value>
</data>
<data name="VerificationEmailNotSent" xml:space="preserve">
<value>Could not send verification email. Try again.</value>
<value>Impossible d'envoyer l'e-mail de vérification. Essayez à nouveau.</value>
<comment>For 2FA</comment>
</data>
<data name="VerificationEmailSent" xml:space="preserve">
<value>Verification email sent.</value>
<value>L'e-mail de vérification a été envoyé.</value>
<comment>For 2FA</comment>
</data>
<data name="YubiKeyInstruction" xml:space="preserve">
<value>Hold your YubiKey NEO against the back of the device to continue.</value>
<value>Maintenez votre YubiKey NEO à l'arrière de l'appareil pour continuer.</value>
</data>
<data name="YubiKeyTitle" xml:space="preserve">
<value>YubiKey NEO Security Key</value>
<value>Clé de sécurité YubiKey NEO</value>
<comment>"YubiKey NEO" is the product name and should not be translated.</comment>
</data>
<data name="AddNewAttachment" xml:space="preserve">
<value>Add New Attachment</value>
<value>Ajouter une nouvelle pièce jointe</value>
</data>
<data name="Attachments" xml:space="preserve">
<value>Attachments</value>
<value>Pièces jointes</value>
</data>
<data name="UnableToDownloadFile" xml:space="preserve">
<value>Unable to download file.</value>
<value>Impossible de télécharger le fichier.</value>
</data>
<data name="UnableToOpenFile" xml:space="preserve">
<value>Your device cannot open this type of file.</value>
<value>Votre appareil ne peut pas ouvrir ce type de fichier.</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Downloading...</value>
<value>Téléchargement...</value>
<comment>Message shown when downloading a file</comment>
</data>
<data name="AttachmentLargeWarning" xml:space="preserve">
<value>This attachment is {0} in size. Are you sure you want to download it onto your device?</value>
<value>Cette pièce jointe est d'une taille de {0}. Êtes-sûr(e) de vouloir la télécharger sur votre appareil ?</value>
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data>
<data name="AuthenticatorKey" xml:space="preserve">
<value>Authenticator Key (TOTP)</value>
<value>Clé d'authentification (TOTP)</value>
</data>
<data name="VerificationCodeTotp" xml:space="preserve">
<value>Verification Code (TOTP)</value>
<value>Code de vérification (TOTP)</value>
<comment>Totp code label</comment>
</data>
<data name="AuthenticatorKeyAdded" xml:space="preserve">
<value>Authenticator key added.</value>
<value>Clé d'authentification ajoutée.</value>
</data>
<data name="AuthenticatorKeyReadError" xml:space="preserve">
<value>Cannot read authenticator key.</value>
<value>Impossible de lire la clé d'authentification.</value>
</data>
<data name="CameraInstructionBottom" xml:space="preserve">
<value>Scanning will happen automatically.</value>
<value>Le scannage se fera automatiquement.</value>
</data>
<data name="CameraInstructionTop" xml:space="preserve">
<value>Point your camera at the QR code.</value>
<value>Pointez votre appareil photo sur le QR code.</value>
</data>
<data name="ScanQrTitle" xml:space="preserve">
<value>Scan QR Code</value>
<value>Scanner le QR code</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Appareil photo</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP copié !</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Copier le TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
<value>Si une clé d'authentification est rattachée à votre identifiant, alors le code de vérification TOTP est automatiquement copié dans le presse-papiers lorsque vous renseignez l'identifiant.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Désactiver la copie automatique du TOTP</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>Une adhésion premium est requises pour utiliser cette fonctionnalité.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Pièce jointe ajoutée</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Pièce jointe supprimée</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Choisir un fichier</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Fichier</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Aucun fichier choisi</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Il n'y a pas de pièces jointes.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Source du fichier</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Fonctionnalité non disponible</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>La taille maximale du fichier est de 100 Mo.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Vous ne pouvez pas utiliser cette fonctionnalité tant que vous ne mettez pas à jour votre clé de chiffrement.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>En savoir plus</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -995,4 +995,48 @@
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -820,7 +820,7 @@
<value>Izradite organizaciju kako biste sigurno dijelili svoje prijave s drugim korisnicima.</value>
</data>
<data name="DisableGADescription" xml:space="preserve">
<value>We use analytics to better learn how the app is being used so that we can make it better. All data collection is completely anonymous.</value>
<value>Koristimo Google analytics kako bismo saznali na koji način se aplikacija upotrebljava, kako bi istu mogli poboljšati. Svako prikupljanje podataka potpuno je anonimno.</value>
</data>
<data name="Features" xml:space="preserve">
<value>Značajke</value>
@@ -942,57 +942,101 @@
<value>Skeniraj QR kôd</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Kamera</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
<value>Fotografije</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP kopiran!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Kopiraj TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
<value>Ako uz Vaše podatke za prijavu postoji i autentifikacijski ključ, kontrolni kôd TOTP automatski se kopira u međuspremnik svaki put kada automatski popunite prijavu.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Onemogući automatsko kopiranje TOTP</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>Za korištenje ove značajke potrebno je premium članstvo.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Prilog dodan</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Prilog obrisan</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Odaberite datoteku</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Datoteka</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Niste odabrali niti jednu datoteku</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Nema privitaka.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Izvor datoteke</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Značajka nije dostupna</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>Maksimalna veličina datoteke je 100 MB.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Ne možete koristiti ovu značajku dok ne ažurirate ključ za šifriranje.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>Saznaj više</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API poslužiteljskog URL-a</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Prilagođeno okruženje</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>Za napredne korisnike. Samostalno možete odrediti osnovni URL svake usluge.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>URL-ovi okoline su spremljeni.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} nije ispravno formatiran.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>URL identiteta poslužitelja</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Vlastito hosting okruženje</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Navedite osnovni URL Vaše lokalno hostirane bitwarden instalacije.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>URL poslužitelja</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>URL poslužitelja web trezora</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Dodirnite ovu obavijest za pregled prijava iz trezora.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

File diff suppressed because it is too large Load Diff

View File

@@ -860,7 +860,7 @@
<comment>For 2FA</comment>
</data>
<data name="LoginUnavailable" xml:space="preserve">
<value>Login Unavailable</value>
<value>Info Masuk Tidak Tersedia</value>
<comment>For 2FA whenever there are no available providers on this device.</comment>
</data>
<data name="NoTwoStepAvailable" xml:space="preserve">
@@ -933,7 +933,7 @@
<value>Cannot read authenticator key.</value>
</data>
<data name="CameraInstructionBottom" xml:space="preserve">
<value>Scanning will happen automatically.</value>
<value>Pemindaian akan terjadi secara otomatis.</value>
</data>
<data name="CameraInstructionTop" xml:space="preserve">
<value>Arahkan kamera Anda ke kode QR.</value>
@@ -948,19 +948,19 @@
<value>Foto</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP disalin!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Salin TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Nonaktifkan salinan TOTP otomatis</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>Keanggotaan premium diperlukan untuk menggunakan fitur ini.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Lampiran ditambahkan</value>
@@ -995,4 +995,48 @@
<data name="LearnMore" xml:space="preserve">
<value>Pelajari Lebih Lanjut</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -995,4 +995,48 @@
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -995,4 +995,48 @@
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

View File

@@ -660,7 +660,7 @@
<value>App Store ratings are reset with every new version of bitwarden. Please consider helping us out with a good review!</value>
</data>
<data name="RegeneratePassword" xml:space="preserve">
<value>Regenerate Password</value>
<value>Gerar nova senha</value>
</data>
<data name="RetypeMasterPassword" xml:space="preserve">
<value>Digite novamente a senha mestre</value>
@@ -723,7 +723,7 @@
<value>Desbloqueio com código PIN</value>
</data>
<data name="Validating" xml:space="preserve">
<value>Validating</value>
<value>Validando</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="VerificationCode" xml:space="preserve">
@@ -844,75 +844,75 @@
<value>Sempre scanear a tela por campos e oferecer auto-preenchimento apenas se um campo de senha for encontrado. Esta é a configuração padrão.</value>
</data>
<data name="CannotOpenApp" xml:space="preserve">
<value>Cannot open the app "{0}".</value>
<value>Não é possível abrir o app "{0}".</value>
<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>Authenticator App</value>
<value>Aplicativo autenticador</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeApp" xml:space="preserve">
<value>Enter the 6 digit verification code from your authenticator app.</value>
<value>Digite o código de verificação de 6 dígitos de seu app autenticador.</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeEmail" xml:space="preserve">
<value>Enter the 6 digit verification code that was emailed to {0}.</value>
<value>Digite o código de verificação de 6 dígitos que foi enviado por email para {0}.</value>
<comment>For 2FA</comment>
</data>
<data name="LoginUnavailable" xml:space="preserve">
<value>Login Unavailable</value>
<value>Início de sessão indisponível</value>
<comment>For 2FA whenever there are no available providers on this device.</comment>
</data>
<data name="NoTwoStepAvailable" xml:space="preserve">
<value>This account has two-step login enabled, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app).</value>
</data>
<data name="RecoveryCodeTitle" xml:space="preserve">
<value>Recovery Code</value>
<value>Código de recuperação</value>
<comment>For 2FA</comment>
</data>
<data name="RememberMe" xml:space="preserve">
<value>Remember me</value>
<value>Lembrar de mim</value>
<comment>Remember my two-step login</comment>
</data>
<data name="SendVerificationCodeAgain" xml:space="preserve">
<value>Send verification code email again</value>
<value>Enviar e-mail do código de verificação novamente</value>
<comment>For 2FA</comment>
</data>
<data name="TwoStepLoginOptions" xml:space="preserve">
<value>Two-step Login Options</value>
<value>Opções de Login em duas etapas</value>
</data>
<data name="UseAnotherTwoStepMethod" xml:space="preserve">
<value>Use another two-step login method</value>
<value>Usar outro método de login em duas etapas</value>
</data>
<data name="VerificationEmailNotSent" xml:space="preserve">
<value>Could not send verification email. Try again.</value>
<value>Não foi possível enviar o email de verificação. Tente novamente.</value>
<comment>For 2FA</comment>
</data>
<data name="VerificationEmailSent" xml:space="preserve">
<value>Verification email sent.</value>
<value>Email de verificação enviado.</value>
<comment>For 2FA</comment>
</data>
<data name="YubiKeyInstruction" xml:space="preserve">
<value>Hold your YubiKey NEO against the back of the device to continue.</value>
<value>Mantenha seu YubiKey NEO contra a parte de trás do aparelho para continuar.</value>
</data>
<data name="YubiKeyTitle" xml:space="preserve">
<value>YubiKey NEO Security Key</value>
<value>Chave de segurança YubiKey NEO</value>
<comment>"YubiKey NEO" is the product name and should not be translated.</comment>
</data>
<data name="AddNewAttachment" xml:space="preserve">
<value>Add New Attachment</value>
<value>Adicionar novo anexo</value>
</data>
<data name="Attachments" xml:space="preserve">
<value>Attachments</value>
<value>Anexos</value>
</data>
<data name="UnableToDownloadFile" xml:space="preserve">
<value>Unable to download file.</value>
<value>O download do arquivo falhou.</value>
</data>
<data name="UnableToOpenFile" xml:space="preserve">
<value>Your device cannot open this type of file.</value>
<value>O seu dispositivo não pode abrir este tipo de arquivo.</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Downloading...</value>
<value>Baixando...</value>
<comment>Message shown when downloading a file</comment>
</data>
<data name="AttachmentLargeWarning" xml:space="preserve">
@@ -920,79 +920,123 @@
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data>
<data name="AuthenticatorKey" xml:space="preserve">
<value>Authenticator Key (TOTP)</value>
<value>Chave do autenticador (TOTP)</value>
</data>
<data name="VerificationCodeTotp" xml:space="preserve">
<value>Verification Code (TOTP)</value>
<value>Código de verificação (TOTP)</value>
<comment>Totp code label</comment>
</data>
<data name="AuthenticatorKeyAdded" xml:space="preserve">
<value>Authenticator key added.</value>
<value>Chave de autenticador adicionada.</value>
</data>
<data name="AuthenticatorKeyReadError" xml:space="preserve">
<value>Cannot read authenticator key.</value>
<value>Não é possível ler a chave de autenticador.</value>
</data>
<data name="CameraInstructionBottom" xml:space="preserve">
<value>Scanning will happen automatically.</value>
<value>Digitalização acontecerá automaticamente.</value>
</data>
<data name="CameraInstructionTop" xml:space="preserve">
<value>Point your camera at the QR code.</value>
<value>Aponte sua câmera para o QR code.</value>
</data>
<data name="ScanQrTitle" xml:space="preserve">
<value>Scan QR Code</value>
<value>Escanear código QR</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Câmera</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
<value>Fotos</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP copiado!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Copiar TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Desativar cópia automática de TOTP</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>Uma conta premium é necessária para usar esse recurso.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Anexo adicionado</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Anexo eliminado</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Escolher arquivo</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Arquivo</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Nenhum arquivo escolhido</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Não existem anexos.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Fonte do arquivo</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Recurso indisponível</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>Tamanho máximo do arquivo é 100 MB.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Você não pode usar esse recurso, até você atualizar sua chave de criptografia.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>Saiba Mais</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -820,7 +820,7 @@
<value>Crie uma organização para partilhar as suas credenciais em segurança com outros utilizadores.</value>
</data>
<data name="DisableGADescription" xml:space="preserve">
<value>We use analytics to better learn how the app is being used so that we can make it better. All data collection is completely anonymous.</value>
<value>Utilizamos analítica para aprender melhor como a aplicação está a ser utilizada para que possamos torná-la melhor. Toda a recolha de dados é completamente anónima.</value>
</data>
<data name="Features" xml:space="preserve">
<value>Funcionalidades</value>
@@ -942,57 +942,101 @@
<value>Digitalizar código QR</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Câmara</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
<value>Fotografias</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP copiado!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Copiar TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
<value>Se o seu início de sessão tem uma chave de autenticador anexada ao mesmo, o código de verificação TOTP é copiado automaticamente para a sua área de transferência quando quer que auto-preencha o início de sessão.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Desativar cópia automática de TOTP</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>É requerida uma adesão premium para utilizar esta funcionalidade.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Anexo adicionado</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Anexo apagado</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Escolher ficheiro</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Ficheiro</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Nenhum ficheiro escolhido</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Não existem anexos.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Fonte de ficheiro</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Funcionalidade indisponível</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>O tamanho máximo do ficheiro é de 100 MB.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Não pode utilizar esta funcionalidade até atualizar a sua chave de encriptação.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>Saber mais</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>URL do servidor da API</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Ambiente personalizado</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>Para utilizadores avançados. Pode especificar o URL de base de cada serviço independentemente.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>Os URLs de ambiente foram guardados.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} não está formatado corretamente.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>URL do servidor de identidade</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Ambiente auto-hospedado</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Especifique o URL de base da sua instalação local do bitwarden.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>URL do servidor</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>URL do servidor do cofre web</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -995,4 +995,48 @@
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
</data>
<data name="ApiUrl" xml:space="preserve">
<value>API Server URL</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Custom Environment</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>For advanced users. You can specify the base URL of each service independently.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>The environment URLs have been saved.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} is not correctly formatted.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>Identity Server URL</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Self-hosted Environment</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specify the base URL of your on-premise hosted bitwarden installation.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>Server URL</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>Web Vault Server URL</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Tap this notification to view logins from your vault.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -556,7 +556,7 @@
<value>Imediat</value>
</data>
<data name="LockOptions" xml:space="preserve">
<value>Opţiuni de blocare</value>
<value>Blocare</value>
</data>
<data name="LoggingIn" xml:space="preserve">
<value>Autentificare...</value>
@@ -714,7 +714,7 @@
<value>Autentificare în două etape</value>
</data>
<data name="TwoStepLoginConfirmation" xml:space="preserve">
<value>Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be enabled on the bitwarden.com web vault. Do you want to visit the website now?</value>
<value>Autentificarea în două etape face ca contul dvs. să fie mai sigur, solicitând să introduceți un cod de securitate dintr-o aplicație de autentificare ori de câte ori vă conectați. Autentificarea în două etape poate fi activată în seiful web bitwarden.com. Doriți să vizitați site-ul acum?</value>
</data>
<data name="UnlockWith" xml:space="preserve">
<value>Deblocare cu {0}</value>
@@ -723,7 +723,7 @@
<value>Deblocare cu codul PIN</value>
</data>
<data name="Validating" xml:space="preserve">
<value>Validating</value>
<value>Validare</value>
<comment>Message shown when interacting with the server</comment>
</data>
<data name="VerificationCode" xml:space="preserve">
@@ -820,7 +820,7 @@
<value>Creați o organizație pentru a partaja în siguranță accesul la datele de conectare cu alţi utilizatori.</value>
</data>
<data name="DisableGADescription" xml:space="preserve">
<value>We use analytics to better learn how the app is being used so that we can make it better. All data collection is completely anonymous.</value>
<value>Utilizăm datele analitice pentru a afla mai bine modul în care este folosită aplicația, astfel încât s-o putem face mai bună. Toate colectările de date sunt complet anonime.</value>
</data>
<data name="Features" xml:space="preserve">
<value>Caracteristici</value>
@@ -848,151 +848,195 @@
<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>Authenticator App</value>
<value>Aplicaţie de autentificare</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeApp" xml:space="preserve">
<value>Enter the 6 digit verification code from your authenticator app.</value>
<value>Introduceţi codul de verificare din 6 cifre din aplicaţia de autentificare.</value>
<comment>For 2FA</comment>
</data>
<data name="EnterVerificationCodeEmail" xml:space="preserve">
<value>Enter the 6 digit verification code that was emailed to {0}.</value>
<value>Introduceţi codul de verificare din 6 cifre, care a fost trimis prin e-mail la {0}.</value>
<comment>For 2FA</comment>
</data>
<data name="LoginUnavailable" xml:space="preserve">
<value>Login Unavailable</value>
<value>Login indisponibil</value>
<comment>For 2FA whenever there are no available providers on this device.</comment>
</data>
<data name="NoTwoStepAvailable" xml:space="preserve">
<value>This account has two-step login enabled, however, none of the configured two-step providers are supported on this device. Please use a supported device and/or add additional providers that are better supported across devices (such as an authenticator app).</value>
<value>Acest cont are activată autentificarea în două etape, cu toate acestea, niciun furnizor de autentificare în două etape configurat nu este acceptat pe acest dispozitiv. Utilizaţi un dispozitiv acceptat şi/sau adăugaţi furnizorii suplimentari care sunt mai bine acceptaţi între dispozitive (cum ar fi o aplicaţie de autentificare).</value>
</data>
<data name="RecoveryCodeTitle" xml:space="preserve">
<value>Recovery Code</value>
<value>Cod de recuperare</value>
<comment>For 2FA</comment>
</data>
<data name="RememberMe" xml:space="preserve">
<value>Remember me</value>
<value>Memorizare</value>
<comment>Remember my two-step login</comment>
</data>
<data name="SendVerificationCodeAgain" xml:space="preserve">
<value>Send verification code email again</value>
<value>Trimitere e-mail cu codul de verificare din nou</value>
<comment>For 2FA</comment>
</data>
<data name="TwoStepLoginOptions" xml:space="preserve">
<value>Two-step Login Options</value>
<value>Opţiuni autentificare în două etape</value>
</data>
<data name="UseAnotherTwoStepMethod" xml:space="preserve">
<value>Use another two-step login method</value>
<value>Utilizaţi o altă metodă de autentificare în două etape</value>
</data>
<data name="VerificationEmailNotSent" xml:space="preserve">
<value>Could not send verification email. Try again.</value>
<value>Nu s-a putut trimite e-mailul de verificare. Încercați din nou.</value>
<comment>For 2FA</comment>
</data>
<data name="VerificationEmailSent" xml:space="preserve">
<value>Verification email sent.</value>
<value>S-a trimis e-mailul de verificare.</value>
<comment>For 2FA</comment>
</data>
<data name="YubiKeyInstruction" xml:space="preserve">
<value>Hold your YubiKey NEO against the back of the device to continue.</value>
<value>Ţineţi apăsat NEO YubiKey din partea din spate a dispozitivului pentru a continua.</value>
</data>
<data name="YubiKeyTitle" xml:space="preserve">
<value>YubiKey NEO Security Key</value>
<value>Cheie de securitate YubiKey NEO</value>
<comment>"YubiKey NEO" is the product name and should not be translated.</comment>
</data>
<data name="AddNewAttachment" xml:space="preserve">
<value>Add New Attachment</value>
<value>Adăugaţi un nou ataşament</value>
</data>
<data name="Attachments" xml:space="preserve">
<value>Attachments</value>
<value>Ataşamente</value>
</data>
<data name="UnableToDownloadFile" xml:space="preserve">
<value>Unable to download file.</value>
<value>Imposibil de descărcat fișierul.</value>
</data>
<data name="UnableToOpenFile" xml:space="preserve">
<value>Your device cannot open this type of file.</value>
<value>Dispozivul nu poate deschide acest tip de fişiere.</value>
</data>
<data name="Downloading" xml:space="preserve">
<value>Downloading...</value>
<value>Descărcare...</value>
<comment>Message shown when downloading a file</comment>
</data>
<data name="AttachmentLargeWarning" xml:space="preserve">
<value>This attachment is {0} in size. Are you sure you want to download it onto your device?</value>
<value>Acest ataşament are {0}. Sunteţi sigur că doriţi să-l descărcaţi pe dispozitivul dvs?</value>
<comment>The placeholder will show the file size of the attachment. Ex "25 MB"</comment>
</data>
<data name="AuthenticatorKey" xml:space="preserve">
<value>Authenticator Key (TOTP)</value>
<value>Cheie autentificare (TOTP)</value>
</data>
<data name="VerificationCodeTotp" xml:space="preserve">
<value>Verification Code (TOTP)</value>
<value>Cod de verificare (TOTP)</value>
<comment>Totp code label</comment>
</data>
<data name="AuthenticatorKeyAdded" xml:space="preserve">
<value>Authenticator key added.</value>
<value>Cheie de autentificare adăugată.</value>
</data>
<data name="AuthenticatorKeyReadError" xml:space="preserve">
<value>Cannot read authenticator key.</value>
<value>Imposibil de citit cheia de autentificare.</value>
</data>
<data name="CameraInstructionBottom" xml:space="preserve">
<value>Scanning will happen automatically.</value>
<value>Se vă scana automat.</value>
</data>
<data name="CameraInstructionTop" xml:space="preserve">
<value>Point your camera at the QR code.</value>
<value>Îndreptați camera spre codul QR.</value>
</data>
<data name="ScanQrTitle" xml:space="preserve">
<value>Scan QR Code</value>
<value>Scanare cod QR</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Cameră</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
<value>Fotografii</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP copiat!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Copiere TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
<value>Dacă datele dvs. de conectare au o cheie de autentificare atașată, codul de verificare TOTP este copiat automat în clipboard de fiecare dată când efectuați automat completarea datelor de conectare.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Dezactivare copiere automată TOTP</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>Un abonament premium este necesar pentru a utiliza această caracteristică.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Ataşament adăugat</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Ataşament şters</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Alegeți fișierul</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Fişier</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Niciun fişier ales</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Nu există niciun ataşament.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Fişierul sursă</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Caracteristică indisponibilă</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>Mărimea maximă a fişierului este de 100 MB.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Veți putea utiliza această caracteristică după ce veți actualiza cheia de criptare.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>Aflați mai multe</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>URL-ul serverului API</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Mediu particularizat</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>Pentru utilizatorii avansați. Puteți specifica adresa URL de bază a fiecărui serviciu independent.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>Adresele URL de mediu au fost salvate.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} nu este formatat corect.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>URL-ul serverului de identitate</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Mediu găzduit în mod automat</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Specificați adresa URL de bază a instalării bitwarden.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>URL-ul serverului</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>URL-ul serverului seifului web</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Atingeți această notificare pentru a vizualiza autentificările din seiful dvs.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

View File

@@ -190,13 +190,13 @@
<comment>Full label for a email address.</comment>
</data>
<data name="EmailUs" xml:space="preserve">
<value>Связь с нами</value>
<value>Напишите нам</value>
</data>
<data name="EmailUsDescription" xml:space="preserve">
<value>Напишите нам на email, чтобы получить помощь или оставить отзыв.</value>
<value>Чтобы получить помощь или оставить отзыв, отправьте нам письмо.</value>
</data>
<data name="EnterPIN" xml:space="preserve">
<value>Введите ваш PIN-код.</value>
<value>Введите PIN-код.</value>
</data>
<data name="Favorites" xml:space="preserve">
<value>Избранное</value>
@@ -280,7 +280,7 @@
<comment>Label for a master password.</comment>
</data>
<data name="More" xml:space="preserve">
<value>Еще</value>
<value>Больше</value>
<comment>Text to define that there are more options things to see.</comment>
</data>
<data name="MyVault" xml:space="preserve">
@@ -474,7 +474,7 @@
<value>Включить автоматическую синхронизацию</value>
</data>
<data name="EnterEmailForHint" xml:space="preserve">
<value>Введите Ваш email для получения подсказки мастер-пароля.</value>
<value>Введите свой email для получения подсказки мастер-пароля.</value>
</data>
<data name="ExntesionReenable" xml:space="preserve">
<value>Повторно включить расширение</value>
@@ -508,7 +508,7 @@
<value>Нажмите на иконку bitwarden в меню, чтобы запустить расширение.</value>
</data>
<data name="ExtensionTurnOn" xml:space="preserve">
<value>Чтобы включить bitwarden в Safari и других приложениях, нажмите Еще в нижней строке меню.</value>
<value>Чтобы включить bitwarden в Safari и других приложениях, нажмите "больше" в нижней строке меню.</value>
</data>
<data name="Favorite" xml:space="preserve">
<value>Избранный</value>
@@ -647,7 +647,7 @@
<value>Вы хотите перезаписать текущий пароль?</value>
</data>
<data name="PushNotificationAlert" xml:space="preserve">
<value>bitwarden автоматически синхронизирует ваше хранилище при помощи push-уведомлений. Для вашего максимального удобства, пожалуйста, выберите Ок при следующем предложении включить push-уведомления.</value>
<value>bitwarden автоматически синхронизирует ваше хранилище при помощи push-уведомлений. Для вашего максимального удобства, пожалуйста, выберите "Ok" при появлении предложения включить push-уведомления.</value>
<comment>Push notifications for apple products</comment>
</data>
<data name="RateTheApp" xml:space="preserve">
@@ -820,7 +820,7 @@
<value>Создайте организацию, чтобы безопасно делиться своими логинами с другими пользователями.</value>
</data>
<data name="DisableGADescription" xml:space="preserve">
<value>We use analytics to better learn how the app is being used so that we can make it better. All data collection is completely anonymous.</value>
<value>Мы используем аналитику для понимания как используется приложение, чтобы сделать его лучше. Все собранные данные полностью анонимны.</value>
</data>
<data name="Features" xml:space="preserve">
<value>Дополнительно</value>
@@ -829,13 +829,13 @@
<value>Сканировать выбор поля пароля</value>
</data>
<data name="AutofillPasswordFieldDescription" xml:space="preserve">
<value>Сканировать и выводить уведомление автозаполнения только при выборе поля ввода пароля. Этот параметр может помочь увеличить время автономной работы.</value>
<value>Сканировать и выводить уведомление автозаполнения только при выборе поля ввода пароля. Этот параметр менее энергозатратен.</value>
</data>
<data name="AutofillPersistNotification" xml:space="preserve">
<value>Постоянное уведомление</value>
</data>
<data name="AutofillPersistNotificationDescription" xml:space="preserve">
<value>Сканирование выполняется только после нажатия постоянно отображаемого уведомления. Этот параметр может помочь увеличить время автономной работы.</value>
<value>Сканирование выполняется только после нажатия постоянно отображаемого уведомления. Этот параметр менее энергозатратен.</value>
</data>
<data name="AutofillAlways" xml:space="preserve">
<value>Сканировать всегда</value>
@@ -942,57 +942,101 @@
<value>Сканировать QR-код</value>
</data>
<data name="Camera" xml:space="preserve">
<value>Camera</value>
<value>Камера</value>
</data>
<data name="Photos" xml:space="preserve">
<value>Photos</value>
<value>Фотографии</value>
</data>
<data name="CopiedTotp" xml:space="preserve">
<value>Copied TOTP!</value>
<value>TOTP скопирован!</value>
</data>
<data name="CopyTotp" xml:space="preserve">
<value>Copy TOTP</value>
<value>Копировать TOTP</value>
</data>
<data name="DisableAutoTotpCopyDescription" xml:space="preserve">
<value>If your login has an authenticator key attached to it, the TOTP verification code is automatically copied to your clipboard whenever you auto-fill the login.</value>
<value>Если ваш логин имеет прикрепленный к нему ключ проверки подлинности, код подтверждения TOTP автоматически копируется в буфер обмена всякий раз, когда вы автоматически заполняете логин.</value>
</data>
<data name="DisableAutoTotpCopy" xml:space="preserve">
<value>Disable Automatic TOTP Copy</value>
<value>Отключить автоматическое копирование TOTP</value>
</data>
<data name="PremiumRequired" xml:space="preserve">
<value>A premium membership is required to use this feature.</value>
<value>Для использования этой функции требуется премиум-статус.</value>
</data>
<data name="AttachementAdded" xml:space="preserve">
<value>Attachment added</value>
<value>Вложение добавлено</value>
</data>
<data name="AttachmentDeleted" xml:space="preserve">
<value>Attachment deleted</value>
<value>Вложение удалено</value>
</data>
<data name="ChooseFile" xml:space="preserve">
<value>Choose File</value>
<value>Выбрать файл</value>
</data>
<data name="File" xml:space="preserve">
<value>File</value>
<value>Файл</value>
</data>
<data name="NoFileChosen" xml:space="preserve">
<value>No file chosen</value>
<value>Файл не выбран</value>
</data>
<data name="NoAttachments" xml:space="preserve">
<value>There are no attachments.</value>
<value>Нет вложений.</value>
</data>
<data name="FileSource" xml:space="preserve">
<value>File Source</value>
<value>Источник файла</value>
</data>
<data name="FeatureUnavailable" xml:space="preserve">
<value>Feature Unavailable</value>
<value>Функция недоступна</value>
</data>
<data name="MaxFileSize" xml:space="preserve">
<value>Maximum file size is 100 MB.</value>
<value>Максимальный размер файла 100 МБ.</value>
</data>
<data name="UpdateKey" xml:space="preserve">
<value>You cannot use this feature until you update your encryption key.</value>
<value>Вы не можете использовать эту функцию, пока не обновите свой ключ шифрования.</value>
</data>
<data name="LearnMore" xml:space="preserve">
<value>Learn More</value>
<value>Узнайть больше</value>
</data>
</root>
<data name="ApiUrl" xml:space="preserve">
<value>API URL-адреса сервера</value>
</data>
<data name="CustomEnvironment" xml:space="preserve">
<value>Пользовательская среда</value>
</data>
<data name="CustomEnvironmentFooter" xml:space="preserve">
<value>Для опытных пользователей. Можно указать URL-адрес отдельно для каждой службы.</value>
</data>
<data name="EnvironmentSaved" xml:space="preserve">
<value>URL-адреса среды сохранены.</value>
</data>
<data name="FormattedIncorrectly" xml:space="preserve">
<value>{0} это неправильный формат.</value>
<comment>Validation error when something is not formatted correctly, such as a URL or email address.</comment>
</data>
<data name="IdentityUrl" xml:space="preserve">
<value>URL-адрес сервера идентификации</value>
<comment>"Identity" refers to an identity server. See more context here https://en.wikipedia.org/wiki/Identity_management</comment>
</data>
<data name="SelfHostedEnvironment" xml:space="preserve">
<value>Среда собственного хостинга</value>
</data>
<data name="SelfHostedEnvironmentFooter" xml:space="preserve">
<value>Укажите URL-адрес bitwarden на вашем сервере.</value>
</data>
<data name="ServerUrl" xml:space="preserve">
<value>URL-адрес сервера</value>
</data>
<data name="WebVaultUrl" xml:space="preserve">
<value>URL-адрес сервера веб-хранилища</value>
</data>
<data name="BitwardenAutofillServiceNotificationContentOld" xml:space="preserve">
<value>Коснитесь этого уведомления, чтобы посмотреть логины из вашего хранилища.</value>
</data>
<data name="CustomFields" xml:space="preserve">
<value>Custom Fields</value>
</data>
<data name="CustomFieldsUpdated" xml:space="preserve">
<value>Custom fields updated.</value>
</data>
<data name="NoCustomFields" xml:space="preserve">
<value>No custom fields. You can fully manage custom fields from the web vault or browser extension.</value>
</data>
</root>

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