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

Compare commits

...

27 Commits

Author SHA1 Message Date
Kyle Spearrin
5350e5385c version bump 2019-06-16 06:57:25 -04:00
Kyle Spearrin
8f18c4fd45 cleartextTrafficPermitted 2019-06-16 06:54:58 -04:00
Kyle Spearrin
8538fbabe5 dont link core lib 2019-06-15 22:50:54 -04:00
Kyle Spearrin
9367b34bbe more linking 2019-06-15 21:58:43 -04:00
Kyle Spearrin
a766044cb4 bump version 2019-06-15 21:13:12 -04:00
Kyle Spearrin
0eb385e49f revert com.android.settings from blacklist 2019-06-15 21:02:38 -04:00
Kyle Spearrin
e30136dace just check if !HasCiphers 2019-06-15 20:44:36 -04:00
Kyle Spearrin
c50dee479a android http client handler 2019-06-15 18:44:08 -04:00
Kyle Spearrin
58ef292fa7 null checks 2019-06-15 00:14:32 -04:00
Kyle Spearrin
61b728fea7 x86 builds as well 2019-06-14 23:32:58 -04:00
Kyle Spearrin
b782eeb839 fixes to 2fa page 2019-06-14 18:08:08 -04:00
Kyle Spearrin
77314d4b8d cleanup search page for ios 2019-06-14 17:40:21 -04:00
Kyle Spearrin
c79d1d24b3 add and more toolbar buttons for ios 2019-06-14 17:31:06 -04:00
Kyle Spearrin
5dbea8ca09 more options on generator and history page 2019-06-14 17:21:17 -04:00
Kyle Spearrin
09a1c17fb4 null checks 2019-06-14 16:53:01 -04:00
Kyle Spearrin
a0632bcac2 null checks 2019-06-14 16:22:56 -04:00
Kyle Spearrin
07d57ebe8c bump version 2019-06-14 08:46:04 -04:00
Kyle Spearrin
325c88018c more menu for ios 2019-06-14 08:45:28 -04:00
Kyle Spearrin
dcb1102746 crash fixes 2019-06-14 08:05:28 -04:00
Kyle Spearrin
636d3c02c4 catch errors 2019-06-13 20:41:24 -04:00
Kyle Spearrin
5b119ded17 x64 builds as well 2019-06-13 16:25:13 -04:00
Kyle Spearrin
f25ae870c5 hebrew fix 2019-06-13 16:07:08 -04:00
Kyle Spearrin
49673262e4 bump version and fix readme 2019-06-13 15:05:31 -04:00
vargbeaumont
3ed814c1f7 Update styles.xml (#537)
Fix black navigation bar on none Google ROMs.
2019-06-13 15:03:00 -04:00
Kyle Spearrin
8b858e5407 new hi-res icon for store 2019-06-13 14:47:05 -04:00
Kyle Spearrin
30145894b6 bump version 2019-06-13 14:11:12 -04:00
Kyle Spearrin
8df4c27203 handle some loading race conditions 2019-06-13 14:08:21 -04:00
43 changed files with 382 additions and 119 deletions

View File

@@ -8,7 +8,7 @@
The Bitwarden mobile application is written in C# with Xamarin Android, Xamarin iOS, and Xamarin Forms.
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android.png" alt="" width="300" height="533" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios.png" alt="" width="300" height="533" />
<img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-android-myvault.png" alt="" width="300" height="533" /> <img src="https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/mobile-ios.png" alt="" width="300" height="533" />
# Build/Run

View File

@@ -33,10 +33,10 @@
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
<AndroidSupportedAbis />
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;Xamarin.Android.Net</AndroidLinkSkip>
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;BitwardenCore;Xamarin.Android.Net</AndroidLinkSkip>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugSymbols>false</DebugSymbols>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
@@ -44,13 +44,15 @@
<WarningLevel>4</WarningLevel>
<AndroidManagedSymbols>true</AndroidManagedSymbols>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<AndroidSupportedAbis />
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;Xamarin.Android.Net</AndroidLinkSkip>
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;BitwardenCore;Xamarin.Android.Net</AndroidLinkSkip>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidLinkMode>Full</AndroidLinkMode>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DebugSymbols>false</DebugSymbols>
<OutputPath>bin\FDroid\</OutputPath>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
@@ -59,18 +61,20 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<DefineConstants>FDROID</DefineConstants>
<AndroidSupportedAbis />
<AndroidSupportedAbis>armeabi-v7a;x86;x86_64;arm64-v8a</AndroidSupportedAbis>
<JavaMaximumHeapSize>1G</JavaMaximumHeapSize>
<AndroidEnableMultiDex>true</AndroidEnableMultiDex>
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;Xamarin.Android.Net</AndroidLinkSkip>
<AndroidLinkSkip>Xamarin.GooglePlayServices.Base;Xamarin.GooglePlayServices.Basement;Xamarin.GooglePlayServices.Measurement;Xamarin.GooglePlayServices.Gcm;BitwardenAndroid;BitwardenApp;BitwardenCore;Xamarin.Android.Net</AndroidLinkSkip>
<AndroidLinkMode>Full</AndroidLinkMode>
</PropertyGroup>
<ItemGroup>
<Reference Include="Mono.Android" />
<Reference Include="Mono.Android.Export" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Xml" />
</ItemGroup>

View File

@@ -66,7 +66,6 @@ namespace Bit.Droid.Autofill
"androidapp://android",
"androidapp://com.x8bit.bitwarden",
"androidapp://com.oneplus.applocker",
"androidapp://com.android.settings",
};
public static async Task<List<FilledItem>> GetFillItemsAsync(Parser parser, ICipherService cipherService)

View File

@@ -15,6 +15,7 @@ using Bit.Droid.Services;
using Bit.Droid.Utilities;
using Plugin.CurrentActivity;
using Plugin.Fingerprint;
using Xamarin.Android.Net;
#if !FDROID
using Android.Gms.Security;
#endif
@@ -39,7 +40,7 @@ namespace Bit.Droid
if(ServiceContainer.RegisteredServices.Count == 0)
{
RegisterLocalServices();
ServiceContainer.Init();
ServiceContainer.Init(new AndroidClientHandler());
if(App.Migration.MigrationHelpers.NeedsMigration())
{
var task = App.Migration.MigrationHelpers.PerformMigrationAsync();

View File

@@ -3,7 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:versionCode="1"
android:versionName="2.0.1"
android:versionName="2.0.6"
package="com.x8bit.bitwarden">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="28" />

View File

@@ -59,7 +59,7 @@
<item name="colorPrimary">@android:color/black</item>
<item name="colorPrimaryDark">@android:color/black</item>
<item name="colorControlNormal">@color/black_border</item>
<item name="android:navigationBarColor">@android:color/black</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style>
<!-- Nord theme -->

View File

@@ -1,5 +1,5 @@
<network-security-config>
<base-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- Trust pre-installed CAs -->
<certificates src="system" />

View File

@@ -54,6 +54,11 @@ namespace Bit.Droid.Services
netLanguage = "zh-Hans";
}
}
else if(androidLanguage.StartsWith("iw"))
{
// Uncomment when we support RTL
// netLanguage = "he";
}
else
{
// Certain languages need to be converted to CultureInfo equivalent

View File

@@ -13,19 +13,20 @@
<pages:TwoFactorPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_cancelItem" />
<ToolbarItem Text="{u:I18n Continue}" Clicked="Continue_Clicked" Order="Primary"
x:Name="_continueItem" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:IsNullConverter x:Key="isNull" />
<ToolbarItem Text="{u:I18n Continue}" Clicked="Continue_Clicked"
x:Name="_continueItem" x:Key="continueItem" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Cancel}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems>
<ScrollView x:Name="_scrollView">
<StackLayout Spacing="10" Padding="0, 0, 0, 10" VerticalOptions="FillAndExpand">
<StackLayout Spacing="20" Padding="0" IsVisible="{Binding TotpMethod, Mode=OneWay}">

View File

@@ -26,7 +26,7 @@ namespace Bit.App.Pages
DuoWebView = _duoWebView;
if(Device.RuntimePlatform == Device.Android)
{
ToolbarItems.RemoveAt(0);
ToolbarItems.Remove(_cancelItem);
}
}
@@ -34,7 +34,7 @@ namespace Bit.App.Pages
public void AddContinueButton()
{
if(ToolbarItems.Count == 0)
if(!ToolbarItems.Contains(_continueItem))
{
ToolbarItems.Add(_continueItem);
}
@@ -42,7 +42,7 @@ namespace Bit.App.Pages
public void RemoveContinueButton()
{
if(ToolbarItems.Count > 0)
if(ToolbarItems.Contains(_continueItem))
{
ToolbarItems.Remove(_continueItem);
}

View File

@@ -19,17 +19,22 @@
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:DateTimeConverter x:Key="dateTime" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_closeItem" x:Key="closeItem" />
<ToolbarItem Text="{u:I18n Clear}"
Clicked="Clear_Clicked"
Order="Secondary"
x:Name="_clearItem"
x:Key="clearItem" />
<ToolbarItem Icon="more_vert.png"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}"
Clicked="More_Clicked"
x:Name="_moreItem"
x:Key="moreItem" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
<ToolbarItem Text="{u:I18n Clear}"
Clicked="Clear_Clicked"
Order="Secondary"
x:Name="_clearItem" />
</ContentPage.ToolbarItems>
<StackLayout x:Name="_mainLayout">
<Label IsVisible="{Binding ShowNoData}"
Text="{u:I18n NoPasswordsToList}"

View File

@@ -1,4 +1,6 @@
using System;
using Bit.App.Resources;
using System;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@@ -12,6 +14,15 @@ namespace Bit.App.Pages
SetActivityIndicator();
_vm = BindingContext as GeneratorHistoryPageViewModel;
_vm.Page = this;
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(_closeItem);
ToolbarItems.Add(_moreItem);
}
else
{
ToolbarItems.Add(_clearItem);
}
}
protected override async void OnAppearing()
@@ -34,5 +45,19 @@ namespace Bit.App.Pages
await Navigation.PopModalAsync();
}
}
private async void More_Clicked(object sender, EventArgs e)
{
if(!DoOnce())
{
return;
}
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel,
null, AppResources.Clear);
if(selection == AppResources.Clear)
{
await _vm.ClearAsync();
}
}
}
}

View File

@@ -12,19 +12,25 @@
<pages:GeneratorPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Select}"
Clicked="Select_Clicked"
Order="Primary"
x:Name="_selectItem" />
<ToolbarItem Text="{u:I18n PasswordHistory}"
Clicked="History_Clicked"
Order="Secondary" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<ToolbarItem Text="{u:I18n Select}"
Clicked="Select_Clicked"
Order="Primary"
x:Name="_selectItem"
x:Key="selectItem" />
<ToolbarItem Text="{u:I18n PasswordHistory}"
Clicked="History_Clicked"
Order="Secondary"
x:Name="_historyItem"
x:Key="historyItem" />
<ToolbarItem Icon="more_vert.png"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}"
Clicked="More_Clicked"
x:Name="_moreItem"
x:Key="moreItem" />
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -1,4 +1,5 @@
using System;
using Bit.App.Resources;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
@@ -19,9 +20,17 @@ namespace Bit.App.Pages
_vm.Page = this;
_fromTabPage = fromTabPage;
_selectAction = selectAction;
if(selectAction == null)
if(selectAction != null)
{
ToolbarItems.Remove(_selectItem);
ToolbarItems.Add(_selectItem);
}
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.Add(_moreItem);
}
else
{
ToolbarItems.Add(_historyItem);
}
}
@@ -59,6 +68,21 @@ namespace Bit.App.Pages
await _vm.CopyAsync();
}
private async void More_Clicked(object sender, EventArgs e)
{
if(!DoOnce())
{
return;
}
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel,
null, AppResources.PasswordHistory);
if(selection == AppResources.PasswordHistory)
{
var page = new GeneratorHistoryPage();
await Navigation.PushModalAsync(new NavigationPage(page));
}
}
private void Select_Clicked(object sender, EventArgs e)
{
_selectAction?.Invoke(_vm.Password);

View File

@@ -46,7 +46,10 @@ namespace Bit.App.Pages
if(EditMode)
{
var folder = await _folderService.GetAsync(FolderId);
Folder = await folder.DecryptAsync();
if(folder != null)
{
Folder = await folder.DecryptAsync();
}
}
else
{
@@ -57,6 +60,10 @@ namespace Bit.App.Pages
public async Task<bool> SubmitAsync()
{
if(Folder == null)
{
return false;
}
if(Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
@@ -93,6 +100,10 @@ namespace Bit.App.Pages
public async Task<bool> DeleteAsync()
{
if(Folder == null)
{
return false;
}
if(Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,

View File

@@ -16,13 +16,15 @@
<pages:FoldersPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<ToolbarItem x:Name="_closeItem" x:Key="closeItem" Text="{u:I18n Close}"
Clicked="Close_Clicked" Order="Primary" Priority="-1" />
<ToolbarItem x:Name="_addItem" x:Key="addItem" Icon="plus.png"
Clicked="AddButton_Clicked" Order="Primary"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n AddItem}" />
<StackLayout x:Name="_mainLayout" x:Key="mainLayout">
<Label IsVisible="{Binding ShowNoData}"
Text="{u:I18n NoFoldersToList}"
@@ -68,7 +70,9 @@
x:Name="_fab"
ImageName="plus.png"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize">
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n AddFolder}">
</fab:FloatingActionButtonView>
</AbsoluteLayout>

View File

@@ -18,10 +18,11 @@ namespace Bit.App.Pages
if(Device.RuntimePlatform == Device.iOS)
{
_absLayout.Children.Remove(_fab);
ToolbarItems.Add(_closeItem);
ToolbarItems.Add(_addItem);
}
else
{
ToolbarItems.RemoveAt(0);
_fab.Clicked = AddButton_Clicked;
}
}

View File

@@ -15,17 +15,7 @@
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
<ToolbarItem Text="{u:I18n Save}" Clicked="Save_Clicked" Order="Primary" />
<ToolbarItem Text="{u:I18n Attachments}"
Clicked="Attachments_Clicked"
Order="Secondary"
x:Name="_attachmentsItem" />
<ToolbarItem Text="{u:I18n Delete}"
Clicked="Delete_Clicked"
Order="Secondary"
IsDestructive="True"
x:Name="_deleteItem" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
@@ -33,16 +23,33 @@
<u:InverseBoolConverter x:Key="inverseBool" />
<u:StringHasValueConverter x:Key="stringHasValue" />
<u:IsNotNullConverter x:Key="notNull" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Key="closeItem" x:Name="_closeItem" />
<ToolbarItem Text="{u:I18n Collections}"
x:Key="collectionsItem"
x:Name="_collectionsItem"
Clicked="Collections_Clicked"
Order="Secondary" />
x:Key="collectionsItem"
x:Name="_collectionsItem"
Clicked="Collections_Clicked"
Order="Secondary" />
<ToolbarItem Text="{u:I18n Share}"
x:Key="shareItem"
x:Name="_shareItem"
Clicked="Share_Clicked"
Order="Secondary" />
x:Key="shareItem"
x:Name="_shareItem"
Clicked="Share_Clicked"
Order="Secondary" />
<ToolbarItem Icon="more_vert.png" Clicked="More_Clicked" Order="Primary" x:Name="_moreItem"
x:Key="moreItem"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
<ToolbarItem Text="{u:I18n Attachments}"
Clicked="Attachments_Clicked"
Order="Secondary"
x:Name="_attachmentsItem"
x:Key="attachmentsItem" />
<ToolbarItem Text="{u:I18n Delete}"
Clicked="Delete_Clicked"
Order="Secondary"
IsDestructive="True"
x:Name="_deleteItem"
x:Key="deleteItem" />
</ResourceDictionary>
</ContentPage.Resources>

View File

@@ -46,14 +46,18 @@ namespace Bit.App.Pages
_vm.DefaultUri = uri ?? appOptions?.Uri;
_vm.Init();
SetActivityIndicator();
if(!_vm.EditMode || Device.RuntimePlatform == Device.iOS)
if(_vm.EditMode && Device.RuntimePlatform == Device.Android)
{
ToolbarItems.Remove(_attachmentsItem);
ToolbarItems.Remove(_deleteItem);
ToolbarItems.Add(_attachmentsItem);
ToolbarItems.Add(_deleteItem);
}
if(Device.RuntimePlatform == Device.Android)
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.RemoveAt(0);
ToolbarItems.Add(_closeItem);
if(_vm.EditMode)
{
ToolbarItems.Add(_moreItem);
}
}
_typePicker.ItemDisplayBinding = new Binding("Key");
@@ -237,6 +241,43 @@ namespace Bit.App.Pages
}
}
private async void More_Clicked(object sender, System.EventArgs e)
{
if(!DoOnce())
{
return;
}
var options = new List<string> { AppResources.Attachments };
if(_vm.EditMode)
{
options.Add(_vm.Cipher.OrganizationId != null ? AppResources.Share : AppResources.Collections);
}
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel,
_vm.EditMode ? AppResources.Delete : null, options.ToArray());
if(selection == AppResources.Delete)
{
if(await _vm.DeleteAsync())
{
await Navigation.PopModalAsync();
}
}
else if(selection == AppResources.Attachments)
{
var page = new AttachmentsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
else if(selection == AppResources.Collections)
{
var page = new CollectionsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
else if(selection == AppResources.Share)
{
var page = new SharePage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
}
private async void Close_Clicked(object sender, System.EventArgs e)
{
if(DoOnce())

View File

@@ -367,6 +367,10 @@ namespace Bit.App.Pages
public async Task<bool> SubmitAsync()
{
if(Cipher == null)
{
return false;
}
if(Xamarin.Essentials.Connectivity.NetworkAccess == Xamarin.Essentials.NetworkAccess.None)
{
await _platformUtilsService.ShowDialogAsync(AppResources.InternetConnectionRequiredMessage,
@@ -381,10 +385,10 @@ namespace Bit.App.Pages
return false;
}
Cipher.Fields = Fields.Any() ? Fields.Select(f => f.Field).ToList() : null;
Cipher.Fields = Fields != null && Fields.Any() ? Fields.Select(f => f.Field).ToList() : null;
if(Cipher.Login != null)
{
Cipher.Login.Uris = Uris.ToList();
Cipher.Login.Uris = Uris?.ToList();
if(!EditMode && Cipher.Type == CipherType.Login && (Cipher.Login.Uris?.Count ?? 0) == 1 &&
string.IsNullOrWhiteSpace(Cipher.Login.Uris.First().Uri))
{
@@ -406,6 +410,10 @@ namespace Bit.App.Pages
}
var cipher = await _cipherService.EncryptAsync(Cipher);
if(cipher == null)
{
return false;
}
try
{
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);

View File

@@ -3,6 +3,8 @@ using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -31,7 +33,15 @@ namespace Bit.App.Pages
base.OnAppearing();
await LoadOnAppearedAsync(_mainLayout, false, async () =>
{
await _vm.LoadAsync();
try
{
await _vm.LoadAsync();
}
catch(Exception e) when(e.Message.Contains("No key."))
{
await Task.Delay(5000);
await _vm.LoadAsync();
}
}, _mainContent);
}

View File

@@ -112,6 +112,10 @@ namespace Bit.App.Pages
public async Task SelectCipherAsync(CipherView cipher, bool fuzzy)
{
if(cipher == null)
{
return;
}
if(_deviceActionService.SystemMajorVersion() < 21)
{
await AppHelpers.CipherListOptions(Page, cipher);

View File

@@ -15,13 +15,11 @@
<pages:CiphersPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:DateTimeConverter x:Key="dateTime" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_closeItem" x:Key="closeItem" />
</ResourceDictionary>
</ContentPage.Resources>
@@ -31,12 +29,14 @@
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Spacing="0"
Padding="0">
Padding="0"
x:Name="_titleLayout">
<controls:MiButton
StyleClass="btn-title, btn-title-platform"
Text="&#xe5c4;"
VerticalOptions="CenterAndExpand"
Clicked="BackButton_Clicked" />
Clicked="BackButton_Clicked"
x:Name="_backButton" />
<SearchBar
x:Name="_searchBar"
HorizontalOptions="FillAndExpand"

View File

@@ -40,9 +40,10 @@ namespace Bit.App.Pages
_vm.PageTitle = AppResources.SearchVault;
}
if(Device.RuntimePlatform == Device.Android)
if(Device.RuntimePlatform == Device.iOS)
{
ToolbarItems.RemoveAt(0);
ToolbarItems.Add(_closeItem);
_titleLayout.Children.Remove(_backButton);
}
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
}
@@ -121,12 +122,9 @@ namespace Bit.App.Pages
}
}
private async void Close_Clicked(object sender, System.EventArgs e)
private void Close_Clicked(object sender, EventArgs e)
{
if(DoOnce())
{
await Navigation.PopModalAsync();
}
GoBack();
}
}
}

View File

@@ -16,7 +16,9 @@
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Icon="search.png" Clicked="Search_Clicked" />
<ToolbarItem Icon="search.png" Clicked="Search_Clicked"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Search}" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
@@ -29,6 +31,10 @@
Clicked="Lock_Clicked" Order="Secondary" />
<ToolbarItem x:Name="_exitItem" x:Key="exitItem" Text="{u:I18n Exit}"
Clicked="Exit_Clicked" Order="Secondary" />
<ToolbarItem x:Name="_addItem" x:Key="addItem" Icon="plus.png"
Clicked="AddButton_Clicked" Order="Primary"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n AddItem}" />
<DataTemplate x:Key="cipherTemplate"
x:DataType="pages:GroupingsPageListItem">
@@ -137,7 +143,9 @@
x:Name="_fab"
ImageName="plus.png"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize">
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n AddItem}">
</fab:FloatingActionButtonView>
</AbsoluteLayout>

View File

@@ -6,7 +6,6 @@ using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Utilities;
using System;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
@@ -50,6 +49,7 @@ namespace Bit.App.Pages
if(Device.RuntimePlatform == Device.iOS)
{
_absLayout.Children.Remove(_fab);
ToolbarItems.Add(_addItem);
}
else
{
@@ -78,6 +78,10 @@ namespace Bit.App.Pages
}
else if(message.Command == "syncCompleted")
{
if(!_vm.LoadedOnce)
{
return;
}
await Task.Delay(500);
Device.BeginInvokeOnMainThread(() =>
{
@@ -92,8 +96,15 @@ namespace Bit.App.Pages
{
if(!_syncService.SyncInProgress)
{
await Task.Delay(500);
await _vm.LoadAsync();
try
{
await _vm.LoadAsync();
}
catch(Exception e) when(e.Message.Contains("No key."))
{
await Task.Delay(5000);
await _vm.LoadAsync();
}
}
else
{
@@ -105,7 +116,7 @@ namespace Bit.App.Pages
}
// Forced sync if for some reason we have no data after a v1 migration
if(_vm.MainPage && !_syncService.SyncInProgress && migratedFromV1.GetValueOrDefault() &&
!_vm.HasCiphers && !_vm.HasFolders &&
!_vm.HasCiphers &&
Xamarin.Essentials.Connectivity.NetworkAccess != Xamarin.Essentials.NetworkAccess.None)
{
var triedV1ReSync = await _storageService.GetAsync<bool?>(Constants.TriedV1Resync);

View File

@@ -126,6 +126,7 @@ namespace Bit.App.Pages
public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; }
public Command RefreshCommand { get; set; }
public Command<CipherView> CipherOptionsCommand { get; set; }
public bool LoadedOnce { get; set; }
public async Task LoadAsync()
{
@@ -134,6 +135,7 @@ namespace Bit.App.Pages
return;
}
_doingLoad = true;
LoadedOnce = true;
ShowNoData = false;
Loading = true;
ShowList = false;

View File

@@ -16,13 +16,6 @@
<pages:ViewPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1" />
<ToolbarItem Text="{u:I18n Edit}" Clicked="EditToolbarItem_Clicked" Order="Primary" />
<ToolbarItem Text="{u:I18n Attachments}" Clicked="Attachments_Clicked" Order="Secondary" />
<ToolbarItem Text="{u:I18n Delete}" Clicked="Delete_Clicked" Order="Secondary" IsDestructive="True" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
@@ -38,6 +31,18 @@
x:Name="_shareItem"
Clicked="Share_Clicked"
Order="Secondary" />
<ToolbarItem Text="{u:I18n Close}" Clicked="Close_Clicked" Order="Primary" Priority="-1"
x:Name="_closeItem" x:Key="closeItem" />
<ToolbarItem Text="{u:I18n Edit}" Clicked="EditToolbarItem_Clicked" Order="Primary"
x:Name="_editItem" x:Key="editItem" />
<ToolbarItem Icon="more_vert.png" Clicked="More_Clicked" Order="Primary"
x:Name="_moreItem" x:Key="moreItem"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n Options}" />
<ToolbarItem Text="{u:I18n Attachments}" Clicked="Attachments_Clicked" Order="Secondary"
x:Name="_attachmentsItem" x:Key="attachmentsItem" />
<ToolbarItem Text="{u:I18n Delete}" Clicked="Delete_Clicked" Order="Secondary" IsDestructive="True"
x:Name="_deleteItem" x:Key="deleteItem" />
<ScrollView x:Key="scrollView" x:Name="_scrollView">
<StackLayout Spacing="20" x:Name="_mainLayout">
@@ -632,7 +637,9 @@
x:Name="_fab"
ImageName="pencil.png"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize">
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize"
AutomationProperties.IsInAccessibleTree="True"
AutomationProperties.Name="{u:I18n EditItem}">
</fab:FloatingActionButtonView>
</AbsoluteLayout>

View File

@@ -1,4 +1,5 @@
using Bit.Core.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -25,15 +26,16 @@ namespace Bit.App.Pages
if(Device.RuntimePlatform == Device.iOS)
{
_absLayout.Children.Remove(_fab);
ToolbarItems.RemoveAt(2);
ToolbarItems.RemoveAt(2);
ToolbarItems.Add(_closeItem);
ToolbarItems.Add(_editItem);
ToolbarItems.Add(_moreItem);
}
else
{
ToolbarItems.RemoveAt(0);
ToolbarItems.RemoveAt(0);
_fab.Clicked = EditButton_Clicked;
_mainLayout.Padding = new Thickness(0, 0, 0, 75);
ToolbarItems.Add(_attachmentsItem);
ToolbarItems.Add(_deleteItem);
}
}
@@ -145,6 +147,40 @@ namespace Bit.App.Pages
}
}
private async void More_Clicked(object sender, System.EventArgs e)
{
if(!DoOnce())
{
return;
}
var options = new List<string> { AppResources.Attachments };
options.Add(_vm.Cipher.OrganizationId != null ? AppResources.Share : AppResources.Collections);
var selection = await DisplayActionSheet(AppResources.Options, AppResources.Cancel,
AppResources.Delete, options.ToArray());
if(selection == AppResources.Delete)
{
if(await _vm.DeleteAsync())
{
await Navigation.PopModalAsync();
}
}
else if(selection == AppResources.Attachments)
{
var page = new AttachmentsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
else if(selection == AppResources.Collections)
{
var page = new CollectionsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
else if(selection == AppResources.Share)
{
var page = new SharePage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
}
}
private async void Close_Clicked(object sender, System.EventArgs e)
{
if(DoOnce())

View File

@@ -94,7 +94,11 @@ namespace Bit.App.Services
if((uri.StartsWith("http://") || uri.StartsWith("https://")) &&
Uri.TryCreate(uri, UriKind.Absolute, out var parsedUri))
{
Browser.OpenAsync(uri, BrowserLaunchMode.External);
try
{
Browser.OpenAsync(uri, BrowserLaunchMode.External);
}
catch(FeatureNotSupportedException) { }
}
else
{

View File

@@ -22,7 +22,7 @@ namespace Bit.Core.Services
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
private readonly HttpClient _httpClient = new HttpClient();
private readonly HttpClient _httpClient;
private readonly ITokenService _tokenService;
private readonly IPlatformUtilsService _platformUtilsService;
private readonly Func<bool, Task> _logoutCallbackAsync;
@@ -31,13 +31,22 @@ namespace Bit.Core.Services
public ApiService(
ITokenService tokenService,
IPlatformUtilsService platformUtilsService,
Func<bool, Task> logoutCallbackAsync)
Func<bool, Task> logoutCallbackAsync,
HttpMessageHandler httpMessageHandler = null)
{
_tokenService = tokenService;
_platformUtilsService = platformUtilsService;
_logoutCallbackAsync = logoutCallbackAsync;
var device = _platformUtilsService.GetDevice();
_deviceType = device.ToString();
if(httpMessageHandler != null)
{
_httpClient = new HttpClient(httpMessageHandler);
}
else
{
_httpClient = new HttpClient();
}
}
public bool UrlsSet { get; private set; }

View File

@@ -310,7 +310,7 @@ namespace Bit.Core.Services
{
options.MinNumber = 9;
}
if(options.MinSpecial == null)
{
options.MinSpecial = 0;
@@ -354,7 +354,15 @@ namespace Bit.Core.Services
}
var tasks = history.Select(async item =>
{
if(item == null)
{
return null;
}
var encrypted = await _cryptoService.EncryptAsync(item.Password);
if(encrypted == null)
{
return null;
}
return new GeneratedPasswordHistory
{
Password = encrypted.EncryptedString,
@@ -362,7 +370,7 @@ namespace Bit.Core.Services
};
});
var h = await Task.WhenAll(tasks);
return h.ToList();
return h.Where(x => x != null).ToList();
}
private async Task<List<GeneratedPasswordHistory>> DecryptHistoryAsync(List<GeneratedPasswordHistory> history)

View File

@@ -2,6 +2,7 @@
using Bit.Core.Services;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace Bit.Core.Utilities
@@ -11,7 +12,7 @@ namespace Bit.Core.Utilities
public static Dictionary<string, object> RegisteredServices { get; set; } = new Dictionary<string, object>();
public static bool Inited { get; set; }
public static void Init()
public static void Init(HttpClientHandler httpClientHandler = null)
{
if(Inited)
{
@@ -31,7 +32,8 @@ namespace Bit.Core.Utilities
var cryptoFunctionService = new PclCryptoFunctionService(cryptoPrimitiveService);
var cryptoService = new CryptoService(storageService, secureStorageService, cryptoFunctionService);
var tokenService = new TokenService(storageService);
var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) => Task.FromResult(0));
var apiService = new ApiService(tokenService, platformUtilsService, (bool expired) => Task.FromResult(0),
httpClientHandler);
var appIdService = new AppIdService(storageService);
var userService = new UserService(storageService, tokenService);
var settingsService = new SettingsService(userService, storageService);

View File

@@ -11,7 +11,7 @@
<key>CFBundleIdentifier</key>
<string>com.8bit.bitwarden</string>
<key>CFBundleShortVersionString</key>
<string>2.0.1</string>
<string>2.0.6</string>
<key>CFBundleVersion</key>
<string>50</string>
<key>CFBundleIconName</key>

View File

@@ -40,14 +40,17 @@ namespace Bit.iOS.Renderers
}
if(e.NewElement != null)
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
if(Element.Uri != null)
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if(e.PropertyName == HybridWebView.UriProperty.PropertyName)
if(e.PropertyName == HybridWebView.UriProperty.PropertyName && Element.Uri != null)
{
Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
}

BIN
src/iOS/Resources/more.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

View File

@@ -132,6 +132,7 @@
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.iOS" />
@@ -331,4 +332,22 @@
<Visible>false</Visible>
</ImageAsset>
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\more%403x.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\more.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\more%402x.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\more_vert%403x.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\more_vert.png" />
</ItemGroup>
<ItemGroup>
<BundleResource Include="Resources\more_vert%402x.png" />
</ItemGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB