mirror of
https://github.com/bitwarden/android.git
synced 2024-12-20 08:12:26 +03:00
Site edit page. Moved site view page to a bound view model. Renamed view models to Models.Page namespace.
This commit is contained in:
parent
a6cdce6bb4
commit
93f1d9ebfb
7 changed files with 295 additions and 78 deletions
|
@ -63,6 +63,7 @@
|
||||||
<Compile Include="Models\Data\SiteData.cs" />
|
<Compile Include="Models\Data\SiteData.cs" />
|
||||||
<Compile Include="Models\Folder.cs" />
|
<Compile Include="Models\Folder.cs" />
|
||||||
<Compile Include="Models\Site.cs" />
|
<Compile Include="Models\Site.cs" />
|
||||||
|
<Compile Include="Models\Page\VaultViewSitePageModel.cs" />
|
||||||
<Compile Include="Pages\LoginNavigationPage.cs" />
|
<Compile Include="Pages\LoginNavigationPage.cs" />
|
||||||
<Compile Include="Pages\MainPage.cs" />
|
<Compile Include="Pages\MainPage.cs" />
|
||||||
<Compile Include="Pages\SyncPage.cs" />
|
<Compile Include="Pages\SyncPage.cs" />
|
||||||
|
@ -98,7 +99,7 @@
|
||||||
<Compile Include="Services\SiteService.cs" />
|
<Compile Include="Services\SiteService.cs" />
|
||||||
<Compile Include="Services\AuthService.cs" />
|
<Compile Include="Services\AuthService.cs" />
|
||||||
<Compile Include="Services\CryptoService.cs" />
|
<Compile Include="Services\CryptoService.cs" />
|
||||||
<Compile Include="Models\View\VaultView.cs" />
|
<Compile Include="Models\Page\VaultListPageModel.cs" />
|
||||||
<Compile Include="Pages\LoginPage.cs" />
|
<Compile Include="Pages\LoginPage.cs" />
|
||||||
<Compile Include="Pages\VaultAddFolderPage.cs" />
|
<Compile Include="Pages\VaultAddFolderPage.cs" />
|
||||||
<Compile Include="Pages\VaultAddSitePage.cs" />
|
<Compile Include="Pages\VaultAddSitePage.cs" />
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
|
||||||
namespace Bit.App.Models.View
|
namespace Bit.App.Models.Page
|
||||||
{
|
{
|
||||||
public class VaultView
|
public class VaultListPageModel
|
||||||
{
|
{
|
||||||
public class Site
|
public class Site
|
||||||
{
|
{
|
||||||
|
@ -44,7 +45,7 @@ namespace Bit.App.Models.View
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Name { get; set; } = "(none)";
|
public string Name { get; set; } = AppResources.FolderNone;
|
||||||
public string FirstLetter { get { return Name.Substring(0, 1); } }
|
public string FirstLetter { get { return Name.Substring(0, 1); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
93
src/App/Models/Page/VaultViewSitePageModel.cs
Normal file
93
src/App/Models/Page/VaultViewSitePageModel.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
|
||||||
|
namespace Bit.App.Models.Page
|
||||||
|
{
|
||||||
|
public class VaultViewSitePageModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private string _name;
|
||||||
|
private string _username;
|
||||||
|
private string _password;
|
||||||
|
private string _uri;
|
||||||
|
private string _notes;
|
||||||
|
private bool _showPassword;
|
||||||
|
|
||||||
|
public VaultViewSitePageModel() { }
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return _name; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_name = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(PageTitle)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Username
|
||||||
|
{
|
||||||
|
get { return _username; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_username = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Username)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Password
|
||||||
|
{
|
||||||
|
get { return _password; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_password = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Password)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Uri
|
||||||
|
{
|
||||||
|
get { return _uri; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_uri = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Uri)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Notes
|
||||||
|
{
|
||||||
|
get { return _notes; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_notes = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Notes)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowNotes)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string PageTitle => Name ?? AppResources.SiteNoName;
|
||||||
|
public bool ShowPassword
|
||||||
|
{
|
||||||
|
get { return _showPassword; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_showPassword = value;
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowPassword)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(MaskedPassword)));
|
||||||
|
PropertyChanged(this, new PropertyChangedEventArgs(nameof(ShowHideText)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string MaskedPassword => ShowPassword ? Password : Password == null ? null : new string('●', Password.Length);
|
||||||
|
public string ShowHideText => ShowPassword ? AppResources.Hide : AppResources.Show;
|
||||||
|
public bool ShowNotes => !string.IsNullOrWhiteSpace(Notes);
|
||||||
|
|
||||||
|
public void Update(Site site)
|
||||||
|
{
|
||||||
|
Name = site.Name?.Decrypt();
|
||||||
|
Username = site.Username?.Decrypt();
|
||||||
|
Password = site.Password?.Decrypt();
|
||||||
|
Uri = site.Uri?.Decrypt();
|
||||||
|
Notes = site.Notes?.Decrypt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Emit;
|
|
||||||
using System.Text;
|
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
|
@ -15,19 +12,26 @@ namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultAddSitePage : ContentPage
|
public class VaultAddSitePage : ContentPage
|
||||||
{
|
{
|
||||||
|
private readonly ISiteService _siteService;
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
private readonly IUserDialogs _userDialogs;
|
||||||
|
private readonly IConnectivity _connectivity;
|
||||||
|
|
||||||
public VaultAddSitePage()
|
public VaultAddSitePage()
|
||||||
{
|
{
|
||||||
var cryptoService = Resolver.Resolve<ICryptoService>();
|
_siteService = Resolver.Resolve<ISiteService>();
|
||||||
var siteService = Resolver.Resolve<ISiteService>();
|
_folderService = Resolver.Resolve<IFolderService>();
|
||||||
var folderService = Resolver.Resolve<IFolderService>();
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
var userDialogs = Resolver.Resolve<IUserDialogs>();
|
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||||
var connectivity = Resolver.Resolve<IConnectivity>();
|
}
|
||||||
|
|
||||||
var folders = folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt());
|
private void Init()
|
||||||
|
{
|
||||||
|
var folders = _folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt());
|
||||||
|
|
||||||
var uriEntry = new Entry { Keyboard = Keyboard.Url };
|
var uriEntry = new Entry { Keyboard = Keyboard.Url };
|
||||||
var nameEntry = new Entry();
|
var nameEntry = new Entry();
|
||||||
var folderPicker = new Picker { Title = "Folder" };
|
var folderPicker = new Picker { Title = AppResources.Folder };
|
||||||
folderPicker.Items.Add(AppResources.FolderNone);
|
folderPicker.Items.Add(AppResources.FolderNone);
|
||||||
folderPicker.SelectedIndex = 0;
|
folderPicker.SelectedIndex = 0;
|
||||||
foreach(var folder in folders)
|
foreach(var folder in folders)
|
||||||
|
@ -60,7 +64,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
|
var saveToolBarItem = new ToolbarItem(AppResources.Save, null, async () =>
|
||||||
{
|
{
|
||||||
if(!connectivity.IsConnected)
|
if(!_connectivity.IsConnected)
|
||||||
{
|
{
|
||||||
AlertNoConnection();
|
AlertNoConnection();
|
||||||
return;
|
return;
|
||||||
|
@ -92,26 +96,26 @@ namespace Bit.App.Pages
|
||||||
site.FolderId = folders.ElementAt(folderPicker.SelectedIndex - 1).Id;
|
site.FolderId = folders.ElementAt(folderPicker.SelectedIndex - 1).Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
var saveTask = siteService.SaveAsync(site);
|
var saveTask = _siteService.SaveAsync(site);
|
||||||
userDialogs.ShowLoading("Saving...", MaskType.Black);
|
_userDialogs.ShowLoading("Saving...", MaskType.Black);
|
||||||
await saveTask;
|
await saveTask;
|
||||||
|
|
||||||
userDialogs.HideLoading();
|
_userDialogs.HideLoading();
|
||||||
await Navigation.PopAsync();
|
await Navigation.PopAsync();
|
||||||
userDialogs.SuccessToast(nameEntry.Text, "New site created.");
|
_userDialogs.SuccessToast(nameEntry.Text, "New site created.");
|
||||||
}, ToolbarItemOrder.Default, 0);
|
}, ToolbarItemOrder.Default, 0);
|
||||||
|
|
||||||
Title = AppResources.AddSite;
|
Title = AppResources.AddSite;
|
||||||
Content = scrollView;
|
Content = scrollView;
|
||||||
ToolbarItems.Add(saveToolBarItem);
|
ToolbarItems.Add(saveToolBarItem);
|
||||||
|
|
||||||
if(!connectivity.IsConnected)
|
if(!_connectivity.IsConnected)
|
||||||
{
|
{
|
||||||
AlertNoConnection();
|
AlertNoConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AlertNoConnection()
|
private void AlertNoConnection()
|
||||||
{
|
{
|
||||||
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
|
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,139 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Acr.UserDialogs;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Plugin.Connectivity.Abstractions;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
using XLabs.Ioc;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultEditSitePage : ContentPage
|
public class VaultEditSitePage : ContentPage
|
||||||
{
|
{
|
||||||
|
private readonly string _siteId;
|
||||||
|
private readonly ISiteService _siteService;
|
||||||
|
private readonly IFolderService _folderService;
|
||||||
|
private readonly IUserDialogs _userDialogs;
|
||||||
|
private readonly IConnectivity _connectivity;
|
||||||
|
|
||||||
public VaultEditSitePage(string siteId)
|
public VaultEditSitePage(string siteId)
|
||||||
{
|
{
|
||||||
Title = "Edit Site " + siteId;
|
_siteId = siteId;
|
||||||
Content = null;
|
_siteService = Resolver.Resolve<ISiteService>();
|
||||||
|
_folderService = Resolver.Resolve<IFolderService>();
|
||||||
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||||
|
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||||
|
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init()
|
||||||
|
{
|
||||||
|
var site = _siteService.GetByIdAsync(_siteId).GetAwaiter().GetResult();
|
||||||
|
if(site == null)
|
||||||
|
{
|
||||||
|
// TODO: handle error. navigate back? should never happen...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var folders = _folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt());
|
||||||
|
|
||||||
|
var uriEntry = new Entry { Keyboard = Keyboard.Url, Text = site.Uri?.Decrypt() };
|
||||||
|
var nameEntry = new Entry { Text = site.Name?.Decrypt() };
|
||||||
|
var folderPicker = new Picker { Title = AppResources.Folder };
|
||||||
|
folderPicker.Items.Add(AppResources.FolderNone);
|
||||||
|
int selectedIndex = 0;
|
||||||
|
int i = 0;
|
||||||
|
foreach(var folder in folders)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if(folder.Id == site.FolderId)
|
||||||
|
{
|
||||||
|
selectedIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
folderPicker.Items.Add(folder.Name.Decrypt());
|
||||||
|
}
|
||||||
|
folderPicker.SelectedIndex = selectedIndex;
|
||||||
|
var usernameEntry = new Entry { Text = site.Username?.Decrypt() };
|
||||||
|
var passwordEntry = new Entry { IsPassword = true, Text = site.Password?.Decrypt() };
|
||||||
|
var notesEditor = new Editor { Text = site.Notes?.Decrypt() };
|
||||||
|
|
||||||
|
var stackLayout = new StackLayout();
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.URI });
|
||||||
|
stackLayout.Children.Add(uriEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Name });
|
||||||
|
stackLayout.Children.Add(nameEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Folder });
|
||||||
|
stackLayout.Children.Add(folderPicker);
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Username });
|
||||||
|
stackLayout.Children.Add(usernameEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Password });
|
||||||
|
stackLayout.Children.Add(passwordEntry);
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Notes });
|
||||||
|
stackLayout.Children.Add(notesEditor);
|
||||||
|
|
||||||
|
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(uriEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(string.IsNullOrWhiteSpace(nameEntry.Text))
|
||||||
|
{
|
||||||
|
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
site.Uri = uriEntry.Text.Encrypt();
|
||||||
|
site.Name = nameEntry.Text.Encrypt();
|
||||||
|
site.Username = usernameEntry.Text?.Encrypt();
|
||||||
|
site.Password = passwordEntry.Text?.Encrypt();
|
||||||
|
site.Notes = notesEditor.Text?.Encrypt();
|
||||||
|
|
||||||
|
if(folderPicker.SelectedIndex > 0)
|
||||||
|
{
|
||||||
|
site.FolderId = folders.ElementAt(folderPicker.SelectedIndex - 1).Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var saveTask = _siteService.SaveAsync(site);
|
||||||
|
_userDialogs.ShowLoading("Saving...", MaskType.Black);
|
||||||
|
await saveTask;
|
||||||
|
|
||||||
|
_userDialogs.HideLoading();
|
||||||
|
await Navigation.PopAsync();
|
||||||
|
_userDialogs.SuccessToast(nameEntry.Text, "Site updated.");
|
||||||
|
}, ToolbarItemOrder.Default, 0);
|
||||||
|
|
||||||
|
Title = "Edit Site";
|
||||||
|
Content = scrollView;
|
||||||
|
ToolbarItems.Add(saveToolBarItem);
|
||||||
|
|
||||||
|
if(!_connectivity.IsConnected)
|
||||||
|
{
|
||||||
|
AlertNoConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AlertNoConnection()
|
||||||
|
{
|
||||||
|
DisplayAlert(AppResources.InternetConnectionRequiredTitle, AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Models.View;
|
using Bit.App.Models.Page;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
@ -28,7 +28,7 @@ namespace Bit.App.Pages
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<VaultView.Folder> Folders { get; private set; } = new ObservableCollection<VaultView.Folder>();
|
public ObservableCollection<VaultListPageModel.Folder> Folders { get; private set; } = new ObservableCollection<VaultListPageModel.Folder>();
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
|
@ -41,7 +41,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
Title = AppResources.MyVault;
|
Title = AppResources.MyVault;
|
||||||
Content = listView;
|
Content = listView;
|
||||||
NavigationPage.SetBackButtonTitle(this, string.Empty);
|
NavigationPage.SetBackButtonTitle(this, "Back");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAppearing()
|
protected override void OnAppearing()
|
||||||
|
@ -59,25 +59,25 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
foreach(var folder in folders)
|
foreach(var folder in folders)
|
||||||
{
|
{
|
||||||
var f = new VaultView.Folder(folder, sites.Where(s => s.FolderId == folder.Id));
|
var f = new VaultListPageModel.Folder(folder, sites.Where(s => s.FolderId == folder.Id));
|
||||||
Folders.Add(f);
|
Folders.Add(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the sites with no folder
|
// add the sites with no folder
|
||||||
var noneFolder = new VaultView.Folder(sites.Where(s => s.FolderId == null));
|
var noneFolder = new VaultListPageModel.Folder(sites.Where(s => s.FolderId == null));
|
||||||
Folders.Add(noneFolder);
|
Folders.Add(noneFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
||||||
{
|
{
|
||||||
var site = e.SelectedItem as VaultView.Site;
|
var site = e.SelectedItem as VaultListPageModel.Site;
|
||||||
Navigation.PushAsync(new VaultViewSitePage(site.Id));
|
Navigation.PushAsync(new VaultViewSitePage(site.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void MoreClickedAsync(object sender, EventArgs e)
|
private async void MoreClickedAsync(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var mi = sender as MenuItem;
|
var mi = sender as MenuItem;
|
||||||
var site = mi.CommandParameter as VaultView.Site;
|
var site = mi.CommandParameter as VaultListPageModel.Site;
|
||||||
var selection = await DisplayActionSheet(AppResources.MoreOptions, AppResources.Cancel, null,
|
var selection = await DisplayActionSheet(AppResources.MoreOptions, AppResources.Cancel, null,
|
||||||
AppResources.View, AppResources.Edit, AppResources.CopyPassword, AppResources.CopyUsername, AppResources.GoToWebsite);
|
AppResources.View, AppResources.Edit, AppResources.CopyPassword, AppResources.CopyUsername, AppResources.GoToWebsite);
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
|
|
||||||
var mi = sender as MenuItem;
|
var mi = sender as MenuItem;
|
||||||
var site = mi.CommandParameter as VaultView.Site;
|
var site = mi.CommandParameter as VaultListPageModel.Site;
|
||||||
var deleteCall = await _siteService.DeleteAsync(site.Id);
|
var deleteCall = await _siteService.DeleteAsync(site.Id);
|
||||||
|
|
||||||
if(deleteCall.Succeeded)
|
if(deleteCall.Succeeded)
|
||||||
|
@ -163,8 +163,8 @@ namespace Bit.App.Pages
|
||||||
deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
|
deleteAction.SetBinding(MenuItem.CommandParameterProperty, new Binding("."));
|
||||||
deleteAction.Clicked += page.DeleteClickedAsync;
|
deleteAction.Clicked += page.DeleteClickedAsync;
|
||||||
|
|
||||||
this.SetBinding<VaultView.Site>(TextProperty, s => s.Name);
|
this.SetBinding<VaultListPageModel.Site>(TextProperty, s => s.Name);
|
||||||
this.SetBinding<VaultView.Site>(DetailProperty, s => s.Username);
|
this.SetBinding<VaultListPageModel.Site>(DetailProperty, s => s.Username);
|
||||||
ContextActions.Add(moreAction);
|
ContextActions.Add(moreAction);
|
||||||
ContextActions.Add(deleteAction);
|
ContextActions.Add(deleteAction);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection.Emit;
|
|
||||||
using System.Text;
|
|
||||||
using Acr.UserDialogs;
|
using Acr.UserDialogs;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models.Page;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using XLabs.Ioc;
|
using XLabs.Ioc;
|
||||||
|
@ -28,25 +25,22 @@ namespace Bit.App.Pages
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init()
|
private VaultViewSitePageModel Model { get; set; } = new VaultViewSitePageModel();
|
||||||
|
|
||||||
|
private void Init()
|
||||||
{
|
{
|
||||||
ToolbarItems.Add(new EditSiteToolBarItem(this, _siteId));
|
ToolbarItems.Add(new EditSiteToolBarItem(this, _siteId));
|
||||||
|
var stackLayout = new StackLayout();
|
||||||
|
|
||||||
var site = _siteService.GetByIdAsync(_siteId).GetAwaiter().GetResult();
|
// Username
|
||||||
if(site == null)
|
|
||||||
{
|
|
||||||
// TODO: handle error. navigate back? should never happen...
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var usernameRow = new StackLayout { Orientation = StackOrientation.Horizontal };
|
var usernameRow = new StackLayout { Orientation = StackOrientation.Horizontal };
|
||||||
var usernameLabel = new Label
|
var usernameLabel = new Label
|
||||||
{
|
{
|
||||||
Text = site.Username?.Decrypt(),
|
|
||||||
HorizontalOptions = LayoutOptions.StartAndExpand,
|
HorizontalOptions = LayoutOptions.StartAndExpand,
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
LineBreakMode = LineBreakMode.TailTruncation
|
LineBreakMode = LineBreakMode.TailTruncation
|
||||||
};
|
};
|
||||||
|
usernameLabel.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Username);
|
||||||
usernameRow.Children.Add(usernameLabel);
|
usernameRow.Children.Add(usernameLabel);
|
||||||
usernameRow.Children.Add(new Button
|
usernameRow.Children.Add(new Button
|
||||||
{
|
{
|
||||||
|
@ -55,63 +49,66 @@ namespace Bit.App.Pages
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
Command = new Command(() => Copy(usernameLabel.Text, AppResources.Username))
|
Command = new Command(() => Copy(usernameLabel.Text, AppResources.Username))
|
||||||
});
|
});
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Username });
|
||||||
|
stackLayout.Children.Add(usernameRow);
|
||||||
|
|
||||||
|
// Password
|
||||||
var passwordRow = new StackLayout { Orientation = StackOrientation.Horizontal };
|
var passwordRow = new StackLayout { Orientation = StackOrientation.Horizontal };
|
||||||
var password = site.Password?.Decrypt();
|
|
||||||
var passwordLabel = new Label
|
var passwordLabel = new Label
|
||||||
{
|
{
|
||||||
Text = new string('●', password.Length),
|
|
||||||
HorizontalOptions = LayoutOptions.StartAndExpand,
|
HorizontalOptions = LayoutOptions.StartAndExpand,
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
LineBreakMode = LineBreakMode.TailTruncation
|
LineBreakMode = LineBreakMode.TailTruncation
|
||||||
};
|
};
|
||||||
|
passwordLabel.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.MaskedPassword);
|
||||||
passwordRow.Children.Add(passwordLabel);
|
passwordRow.Children.Add(passwordLabel);
|
||||||
var togglePasswordButton = new Button
|
var togglePasswordButton = new Button
|
||||||
{
|
{
|
||||||
Text = AppResources.Show,
|
|
||||||
HorizontalOptions = LayoutOptions.End,
|
HorizontalOptions = LayoutOptions.End,
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
Command = new Command((self) => TogglePassword(self as Button, passwordLabel, password))
|
Command = new Command(() => Model.ShowPassword = !Model.ShowPassword)
|
||||||
};
|
};
|
||||||
togglePasswordButton.CommandParameter = togglePasswordButton;
|
togglePasswordButton.CommandParameter = togglePasswordButton;
|
||||||
|
togglePasswordButton.SetBinding<VaultViewSitePageModel>(Button.TextProperty, s => s.ShowHideText);
|
||||||
passwordRow.Children.Add(togglePasswordButton);
|
passwordRow.Children.Add(togglePasswordButton);
|
||||||
passwordRow.Children.Add(new Button
|
passwordRow.Children.Add(new Button
|
||||||
{
|
{
|
||||||
Text = AppResources.Copy,
|
Text = AppResources.Copy,
|
||||||
HorizontalOptions = LayoutOptions.End,
|
HorizontalOptions = LayoutOptions.End,
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
Command = new Command(() => Copy(password, AppResources.Password))
|
Command = new Command(() => Copy(Model.Password, AppResources.Password))
|
||||||
});
|
});
|
||||||
|
stackLayout.Children.Add(new Label { Text = AppResources.Password });
|
||||||
|
stackLayout.Children.Add(passwordRow);
|
||||||
|
|
||||||
|
// URI
|
||||||
var uriRow = new StackLayout { Orientation = StackOrientation.Horizontal };
|
var uriRow = new StackLayout { Orientation = StackOrientation.Horizontal };
|
||||||
var uri = site.Uri?.Decrypt();
|
var uriLabel = new Label
|
||||||
uriRow.Children.Add(new Label
|
|
||||||
{
|
{
|
||||||
Text = uri,
|
|
||||||
HorizontalOptions = LayoutOptions.StartAndExpand,
|
HorizontalOptions = LayoutOptions.StartAndExpand,
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
LineBreakMode = LineBreakMode.TailTruncation
|
LineBreakMode = LineBreakMode.TailTruncation
|
||||||
});
|
};
|
||||||
|
uriLabel.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Uri);
|
||||||
|
uriRow.Children.Add(uriLabel);
|
||||||
uriRow.Children.Add(new Button
|
uriRow.Children.Add(new Button
|
||||||
{
|
{
|
||||||
Text = AppResources.Launch,
|
Text = AppResources.Launch,
|
||||||
HorizontalOptions = LayoutOptions.End,
|
HorizontalOptions = LayoutOptions.End,
|
||||||
VerticalOptions = LayoutOptions.Center,
|
VerticalOptions = LayoutOptions.Center,
|
||||||
Command = new Command(() => Device.OpenUri(new Uri(uri)))
|
Command = new Command(() => Device.OpenUri(new Uri(uriLabel.Text)))
|
||||||
});
|
});
|
||||||
|
|
||||||
var stackLayout = new StackLayout();
|
|
||||||
stackLayout.Children.Add(new Label { Text = AppResources.Username });
|
|
||||||
stackLayout.Children.Add(usernameRow);
|
|
||||||
stackLayout.Children.Add(new Label { Text = AppResources.Password });
|
|
||||||
stackLayout.Children.Add(passwordRow);
|
|
||||||
stackLayout.Children.Add(new Label { Text = AppResources.Website });
|
stackLayout.Children.Add(new Label { Text = AppResources.Website });
|
||||||
stackLayout.Children.Add(uriRow);
|
stackLayout.Children.Add(uriRow);
|
||||||
if(site.Notes != null)
|
|
||||||
{
|
// Notes
|
||||||
stackLayout.Children.Add(new Label { Text = AppResources.Notes });
|
var notes = new Label { Text = AppResources.Notes };
|
||||||
stackLayout.Children.Add(new Label { Text = site.Notes.Decrypt() });
|
notes.SetBinding<VaultViewSitePageModel>(Label.IsVisibleProperty, s => s.ShowNotes);
|
||||||
}
|
stackLayout.Children.Add(notes);
|
||||||
|
var notesLabel = new Label();
|
||||||
|
notesLabel.SetBinding<VaultViewSitePageModel>(Label.TextProperty, s => s.Notes);
|
||||||
|
notesLabel.SetBinding<VaultViewSitePageModel>(Label.IsVisibleProperty, s => s.ShowNotes);
|
||||||
|
stackLayout.Children.Add(notesLabel);
|
||||||
|
|
||||||
var scrollView = new ScrollView
|
var scrollView = new ScrollView
|
||||||
{
|
{
|
||||||
|
@ -119,22 +116,21 @@ namespace Bit.App.Pages
|
||||||
Orientation = ScrollOrientation.Vertical
|
Orientation = ScrollOrientation.Vertical
|
||||||
};
|
};
|
||||||
|
|
||||||
Title = site.Name?.Decrypt() ?? AppResources.SiteNoName;
|
SetBinding(Page.TitleProperty, new Binding("PageTitle"));
|
||||||
Content = scrollView;
|
Content = scrollView;
|
||||||
|
BindingContext = Model;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TogglePassword(Button toggleButton, Label passwordLabel, string password)
|
protected override void OnAppearing()
|
||||||
{
|
{
|
||||||
if(toggleButton.Text == AppResources.Show)
|
var site = _siteService.GetByIdAsync(_siteId).GetAwaiter().GetResult();
|
||||||
|
if(site == null)
|
||||||
{
|
{
|
||||||
toggleButton.Text = AppResources.Hide;
|
// TODO: handle error. navigate back? should never happen...
|
||||||
passwordLabel.Text = password;
|
return;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toggleButton.Text = AppResources.Show;
|
|
||||||
passwordLabel.Text = new string('●', password.Length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model.Update(site);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Copy(string copyText, string alertLabel)
|
private void Copy(string copyText, string alertLabel)
|
||||||
|
|
Loading…
Reference in a new issue