Settings options added to table. Folder add/edit/list pages for settings.

This commit is contained in:
Kyle Spearrin 2016-05-17 23:09:20 -04:00
parent 72c807a5b2
commit 08875f7c5a
10 changed files with 420 additions and 116 deletions

View file

@ -76,12 +76,15 @@
<Compile Include="Abstractions\IDataObject.cs" />
<Compile Include="Models\Data\SiteData.cs" />
<Compile Include="Models\Folder.cs" />
<Compile Include="Models\Page\SettingsFolderPageModel.cs" />
<Compile Include="Models\Site.cs" />
<Compile Include="Models\Page\VaultViewSitePageModel.cs" />
<Compile Include="Pages\LoginNavigationPage.cs" />
<Compile Include="Pages\MainPage.cs" />
<Compile Include="Pages\SettingsEditFolderPage.cs" />
<Compile Include="Pages\SyncPage.cs" />
<Compile Include="Pages\SettingsPage.cs" />
<Compile Include="Pages\SettingsListFoldersPage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Abstractions\Repositories\ISiteRepository.cs" />
<Compile Include="Repositories\ApiRepository.cs" />
@ -115,11 +118,11 @@
<Compile Include="Services\CryptoService.cs" />
<Compile Include="Models\Page\VaultListPageModel.cs" />
<Compile Include="Pages\LoginPage.cs" />
<Compile Include="Pages\VaultAddFolderPage.cs" />
<Compile Include="Pages\SettingsAddFolderPage.cs" />
<Compile Include="Pages\VaultAddSitePage.cs" />
<Compile Include="Pages\VaultViewSitePage.cs" />
<Compile Include="Pages\VaultEditSitePage.cs" />
<Compile Include="Pages\VaultListPage.cs" />
<Compile Include="Pages\VaultListSitesPage.cs" />
<Compile Include="Utilities\Extentions.cs" />
<Compile Include="Utilities\TokenHttpRequestMessage.cs" />
</ItemGroup>

View file

@ -0,0 +1,14 @@
namespace Bit.App.Models.Page
{
public class SettingsFolderPageModel
{
public SettingsFolderPageModel(Folder folder)
{
Id = folder.Id;
Name = folder.Name?.Decrypt();
}
public string Id { get; set; }
public string Name { get; set; }
}
}

View file

@ -13,7 +13,7 @@ namespace Bit.App.Pages
TintColor = Color.FromHex("ffffff");
var settingsNavigation = new ExtendedNavigationPage(new SettingsPage());
var vaultNavigation = new ExtendedNavigationPage(new VaultListPage());
var vaultNavigation = new ExtendedNavigationPage(new VaultListSitesPage());
var syncNavigation = new ExtendedNavigationPage(new SyncPage());
vaultNavigation.Title = AppResources.MyVault;

View file

@ -0,0 +1,100 @@
using System;
using Acr.UserDialogs;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Models;
using Bit.App.Resources;
using Plugin.Connectivity.Abstractions;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.App.Pages
{
public class SettingsAddFolderPage : ContentPage
{
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
public SettingsAddFolderPage()
{
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
Init();
}
private void Init()
{
var nameCell = new FormEntryCell(AppResources.Name);
var mainTable = new ExtendedTableView
{
Intent = TableIntent.Settings,
EnableScrolling = false,
HasUnevenRows = true,
EnableSelection = false,
Root = new TableRoot
{
new TableSection()
{
nameCell
}
}
};
if(Device.OS == TargetPlatform.iOS)
{
mainTable.RowHeight = -1;
mainTable.EstimatedRowHeight = 70;
}
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
{
if(!_connectivity.IsConnected)
{
AlertNoConnection();
return;
}
if(string.IsNullOrWhiteSpace(nameCell.Entry.Text))
{
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok);
return;
}
var folder = new Folder
{
Name = nameCell.Entry.Text.Encrypt()
};
var saveTask = _folderService.SaveAsync(folder);
_userDialogs.ShowLoading("Saving...", MaskType.Black);
await saveTask;
_userDialogs.HideLoading();
await Navigation.PopModalAsync();
_userDialogs.SuccessToast(nameCell.Entry.Text, "New folder created.");
}, ToolbarItemOrder.Default, 0);
Title = "Add Folder";
Content = mainTable;
ToolbarItems.Add(saveToolBarItem);
if(Device.OS == TargetPlatform.iOS)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel"));
}
if(!_connectivity.IsConnected)
{
AlertNoConnection();
}
}
private void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
}
}
}

View file

@ -0,0 +1,106 @@
using System;
using Acr.UserDialogs;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Resources;
using Plugin.Connectivity.Abstractions;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.App.Pages
{
public class SettingsEditFolderPage : ContentPage
{
private readonly string _folderId;
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
private readonly IConnectivity _connectivity;
public SettingsEditFolderPage(string folderId)
{
_folderId = folderId;
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_connectivity = Resolver.Resolve<IConnectivity>();
Init();
}
private void Init()
{
var folder = _folderService.GetByIdAsync(_folderId).GetAwaiter().GetResult();
if(folder == null)
{
// TODO: handle error. navigate back? should never happen...
return;
}
var nameCell = new FormEntryCell(AppResources.Name);
nameCell.Entry.Text = folder.Name.Decrypt();
var mainTable = new ExtendedTableView
{
Intent = TableIntent.Settings,
EnableScrolling = false,
HasUnevenRows = true,
EnableSelection = false,
Root = new TableRoot
{
new TableSection()
{
nameCell
}
}
};
if(Device.OS == TargetPlatform.iOS)
{
mainTable.RowHeight = -1;
mainTable.EstimatedRowHeight = 70;
}
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
{
if(!_connectivity.IsConnected)
{
AlertNoConnection();
return;
}
if(string.IsNullOrWhiteSpace(nameCell.Entry.Text))
{
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok);
return;
}
folder.Name = nameCell.Entry.Text.Encrypt();
var saveTask = _folderService.SaveAsync(folder);
_userDialogs.ShowLoading("Saving...", MaskType.Black);
await saveTask;
_userDialogs.HideLoading();
await Navigation.PopModalAsync();
_userDialogs.SuccessToast(nameCell.Entry.Text, "Folder updated.");
}, ToolbarItemOrder.Default, 0);
Title = "Edit Folder";
Content = mainTable;
ToolbarItems.Add(saveToolBarItem);
if(Device.OS == TargetPlatform.iOS)
{
ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel"));
}
if(!_connectivity.IsConnected)
{
AlertNoConnection();
}
}
private void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
}
}
}

View file

@ -0,0 +1,97 @@
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Acr.UserDialogs;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Models.Page;
using Bit.App.Resources;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.App.Pages
{
public class SettingsListFoldersPage : ContentPage
{
private readonly IFolderService _folderService;
private readonly IUserDialogs _userDialogs;
public SettingsListFoldersPage()
{
_folderService = Resolver.Resolve<IFolderService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
Init();
}
public ObservableCollection<SettingsFolderPageModel> Folders { get; private set; } = new ObservableCollection<SettingsFolderPageModel>();
private void Init()
{
ToolbarItems.Add(new AddFolderToolBarItem(this));
var listView = new ListView
{
ItemsSource = Folders,
SeparatorColor = Color.FromHex("d2d6de")
};
listView.ItemSelected += FolderSelected;
listView.ItemTemplate = new DataTemplate(() => new SettingsFolderListViewCell(this));
Title = "Folders";
Content = listView;
}
protected override void OnAppearing()
{
base.OnAppearing();
LoadFoldersAsync().Wait();
}
private async Task LoadFoldersAsync()
{
Folders.Clear();
var folders = await _folderService.GetAllAsync();
foreach(var folder in folders)
{
var f = new SettingsFolderPageModel(folder);
Folders.Add(f);
}
}
private void FolderSelected(object sender, SelectedItemChangedEventArgs e)
{
var folder = e.SelectedItem as SettingsFolderPageModel;
var page = new ExtendedNavigationPage(new SettingsEditFolderPage(folder.Id));
Navigation.PushModalAsync(page);
}
private class AddFolderToolBarItem : ToolbarItem
{
private readonly SettingsListFoldersPage _page;
public AddFolderToolBarItem(SettingsListFoldersPage page)
{
_page = page;
Text = AppResources.Add;
Icon = "ion-plus";
Clicked += ClickedItem;
}
private async void ClickedItem(object sender, EventArgs e)
{
var page = new ExtendedNavigationPage(new SettingsAddFolderPage());
await _page.Navigation.PushModalAsync(page);
}
}
private class SettingsFolderListViewCell : ExtendedTextCell
{
public SettingsFolderListViewCell(SettingsListFoldersPage page)
{
this.SetBinding<SettingsFolderPageModel>(TextProperty, s => s.Name);
TextColor = Color.FromHex("333333");
}
}
}
}

View file

@ -4,59 +4,134 @@ using Bit.App.Resources;
using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Controls;
using Acr.UserDialogs;
namespace Bit.App.Pages
{
public class SettingsPage : ContentPage
{
private readonly IAuthService _authService;
private readonly IUserDialogs _userDialogs;
public SettingsPage()
{
_authService = Resolver.Resolve<IAuthService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
Init();
}
private void Init()
{
var foldersCell = new ExtendedTextCell { Text = "Folders", ShowDisclousure = true };
var touchIdCell = new SwitchCell
{
Text = "Use Touch ID"
};
touchIdCell.Tapped += TouchIdCell_Tapped;
var lockOnExitCell = new SwitchCell
{
Text = "Lock Immediately On Exit"
};
lockOnExitCell.Tapped += LockOnExitCell_Tapped;
var changeMasterPasswordCell = new ExtendedTextCell
{
Text = "Change Master Password"
};
changeMasterPasswordCell.Tapped += ChangeMasterPasswordCell_Tapped;
var foldersCell = new ExtendedTextCell
{
Text = "Folders",
ShowDisclousure = true
};
foldersCell.Tapped += FoldersCell_Tapped;
var lockCell = new ExtendedTextCell
{
Text = "Lock"
};
lockCell.Tapped += LockCell_Tapped;
var logOutCell = new ExtendedTextCell
{
Text = "Log Out"
};
logOutCell.Tapped += LogOutCell_Tapped;
var table = new ExtendedTableView
{
EnableScrolling = false,
EnableScrolling = true,
Intent = TableIntent.Menu,
Root = new TableRoot
{
new TableSection("Security")
{
touchIdCell,
lockOnExitCell,
changeMasterPasswordCell
},
new TableSection("Manage Folders")
{
foldersCell
},
new TableSection("Current Session")
{
lockCell,
logOutCell
}
}
};
var logoutButton = new Button
var scrollView = new ScrollView
{
Text = AppResources.LogOut,
Command = new Command(() =>
{
_authService.LogOut();
Application.Current.MainPage = new LoginNavigationPage();
})
Content = table
};
var stackLayout = new StackLayout { };
stackLayout.Children.Add(table);
stackLayout.Children.Add(logoutButton);
Title = AppResources.Settings;
Content = stackLayout;
Content = table;
}
private void LockCell_Tapped(object sender, EventArgs e)
{
}
private async void LogOutCell_Tapped(object sender, EventArgs e)
{
if(!await _userDialogs.ConfirmAsync("Are you sure you want to log out?", null, AppResources.Yes, AppResources.Cancel))
{
return;
}
_authService.LogOut();
Application.Current.MainPage = new LoginNavigationPage();
}
private void LockOnExitCell_Tapped(object sender, EventArgs e)
{
}
private async void ChangeMasterPasswordCell_Tapped(object sender, EventArgs e)
{
if(!await _userDialogs.ConfirmAsync("You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?", null, AppResources.Yes, AppResources.Cancel))
{
return;
}
Device.OpenUri(new Uri("https://vault.bitwarden.com"));
}
private void TouchIdCell_Tapped(object sender, EventArgs e)
{
}
private void FoldersCell_Tapped(object sender, EventArgs e)
{
Navigation.PushAsync(new SettingsListFoldersPage());
}
}
}

View file

@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using Acr.UserDialogs;
using Bit.App.Abstractions;
using Bit.App.Models;
using Bit.App.Resources;
using Plugin.Connectivity.Abstractions;
using Xamarin.Forms;
using XLabs.Ioc;
namespace Bit.App.Pages
{
public class VaultAddFolderPage : ContentPage
{
public VaultAddFolderPage()
{
var cryptoService = Resolver.Resolve<ICryptoService>();
var folderService = Resolver.Resolve<IFolderService>();
var userDialogs = Resolver.Resolve<IUserDialogs>();
var connectivity = Resolver.Resolve<IConnectivity>();
var nameEntry = new Entry();
var stackLayout = new StackLayout();
stackLayout.Children.Add(new Label { Text = AppResources.Name });
stackLayout.Children.Add(nameEntry);
var scrollView = new ScrollView
{
Content = stackLayout,
Orientation = ScrollOrientation.Vertical
};
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
{
if(!connectivity.IsConnected)
{
AlertNoConnection();
return;
}
if(string.IsNullOrWhiteSpace(nameEntry.Text))
{
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok);
return;
}
var folder = new Folder
{
Name = nameEntry.Text.Encrypt()
};
var saveTask = folderService.SaveAsync(folder);
userDialogs.ShowLoading("Saving...", MaskType.Black);
await saveTask;
userDialogs.HideLoading();
await Navigation.PopAsync();
userDialogs.SuccessToast(nameEntry.Text, "New folder created.");
}, ToolbarItemOrder.Default, 0);
Title = "Add Folder";
Content = scrollView;
ToolbarItems.Add(saveToolBarItem);
if(!connectivity.IsConnected)
{
AlertNoConnection();
}
}
public void AlertNoConnection()
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
}
}
}

View file

@ -120,7 +120,7 @@ namespace Bit.App.Pages
await saveTask;
_userDialogs.HideLoading();
await Navigation.PopAsync();
await Navigation.PopModalAsync();
_userDialogs.SuccessToast(nameCell.Entry.Text, "New site created.");
}, ToolbarItemOrder.Default, 0);
@ -142,15 +142,6 @@ namespace Bit.App.Pages
{
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
}
private class FormEntryStackLayout : StackLayout
{
public FormEntryStackLayout()
{
Padding = new Thickness(15, 15, 15, 0);
BackgroundColor = Color.White;
}
}
}
}

View file

@ -12,14 +12,14 @@ using XLabs.Ioc;
namespace Bit.App.Pages
{
public class VaultListPage : ContentPage
public class VaultListSitesPage : ContentPage
{
private readonly IFolderService _folderService;
private readonly ISiteService _siteService;
private readonly IUserDialogs _userDialogs;
private readonly IClipboardService _clipboardService;
public VaultListPage()
public VaultListSitesPage()
{
_folderService = Resolver.Resolve<IFolderService>();
_siteService = Resolver.Resolve<ISiteService>();
@ -145,9 +145,9 @@ namespace Bit.App.Pages
private class AddSiteToolBarItem : ToolbarItem
{
private readonly VaultListPage _page;
private readonly VaultListSitesPage _page;
public AddSiteToolBarItem(VaultListPage page)
public AddSiteToolBarItem(VaultListSitesPage page)
{
_page = page;
Text = AppResources.Add;
@ -164,7 +164,7 @@ namespace Bit.App.Pages
private class VaultListViewCell : ExtendedTextCell
{
public VaultListViewCell(VaultListPage page)
public VaultListViewCell(VaultListSitesPage page)
{
var moreAction = new MenuItem { Text = AppResources.More };
moreAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
@ -181,13 +181,12 @@ namespace Bit.App.Pages
TextColor = Color.FromHex("333333");
DetailColor = Color.FromHex("777777");
BackgroundColor = Color.White;
}
}
private class VaultListHeaderViewCell : ViewCell
{
public VaultListHeaderViewCell(VaultListPage page)
public VaultListHeaderViewCell(VaultListSitesPage page)
{
var image = new Image
{