2016-05-02 09:52:09 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Linq;
|
2016-05-04 02:49:49 +03:00
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Acr.UserDialogs;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
using Bit.App.Abstractions;
|
2016-05-13 07:11:32 +03:00
|
|
|
|
using Bit.App.Controls;
|
2016-05-08 06:11:47 +03:00
|
|
|
|
using Bit.App.Models.Page;
|
2016-05-07 10:06:27 +03:00
|
|
|
|
using Bit.App.Resources;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
using Xamarin.Forms;
|
|
|
|
|
using XLabs.Ioc;
|
2016-05-19 03:29:03 +03:00
|
|
|
|
using Bit.App.Utilities;
|
2016-06-28 07:55:53 +03:00
|
|
|
|
using PushNotification.Plugin.Abstractions;
|
|
|
|
|
using Plugin.Settings.Abstractions;
|
2016-07-02 01:54:00 +03:00
|
|
|
|
using Plugin.Connectivity.Abstractions;
|
2016-07-07 05:59:13 +03:00
|
|
|
|
using System.Collections.Generic;
|
2016-08-14 08:42:18 +03:00
|
|
|
|
using System.Threading;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-05-03 00:50:16 +03:00
|
|
|
|
namespace Bit.App.Pages
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
2016-06-28 02:53:31 +03:00
|
|
|
|
public class VaultListSitesPage : ExtendedContentPage
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
|
|
|
|
private readonly IFolderService _folderService;
|
|
|
|
|
private readonly ISiteService _siteService;
|
2016-05-04 02:49:49 +03:00
|
|
|
|
private readonly IUserDialogs _userDialogs;
|
2016-07-02 01:54:00 +03:00
|
|
|
|
private readonly IConnectivity _connectivity;
|
2016-05-07 20:42:09 +03:00
|
|
|
|
private readonly IClipboardService _clipboardService;
|
2016-07-12 06:55:16 +03:00
|
|
|
|
private readonly ISyncService _syncService;
|
2016-06-28 07:55:53 +03:00
|
|
|
|
private readonly IPushNotification _pushNotification;
|
|
|
|
|
private readonly ISettings _settings;
|
2016-06-15 06:23:05 +03:00
|
|
|
|
private readonly bool _favorites;
|
2016-08-06 06:58:31 +03:00
|
|
|
|
private bool _loadExistingData;
|
2016-08-14 08:42:18 +03:00
|
|
|
|
private CancellationTokenSource _filterResultsCancellationTokenSource;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-06-15 06:23:05 +03:00
|
|
|
|
public VaultListSitesPage(bool favorites)
|
2016-08-06 18:43:22 +03:00
|
|
|
|
: base(true)
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
2016-06-15 06:23:05 +03:00
|
|
|
|
_favorites = favorites;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
_folderService = Resolver.Resolve<IFolderService>();
|
|
|
|
|
_siteService = Resolver.Resolve<ISiteService>();
|
2016-07-02 01:54:00 +03:00
|
|
|
|
_connectivity = Resolver.Resolve<IConnectivity>();
|
2016-05-04 02:49:49 +03:00
|
|
|
|
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
2016-05-07 20:42:09 +03:00
|
|
|
|
_clipboardService = Resolver.Resolve<IClipboardService>();
|
2016-07-12 06:55:16 +03:00
|
|
|
|
_syncService = Resolver.Resolve<ISyncService>();
|
2016-06-28 07:55:53 +03:00
|
|
|
|
_pushNotification = Resolver.Resolve<IPushNotification>();
|
|
|
|
|
_settings = Resolver.Resolve<ISettings>();
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-08-06 06:58:31 +03:00
|
|
|
|
var cryptoService = Resolver.Resolve<ICryptoService>();
|
|
|
|
|
_loadExistingData = !_settings.GetValueOrDefault(Constants.FirstVaultLoad, true) || !cryptoService.KeyChanged;
|
|
|
|
|
|
2016-05-04 02:49:49 +03:00
|
|
|
|
Init();
|
|
|
|
|
}
|
2016-05-03 01:35:01 +03:00
|
|
|
|
|
2016-07-11 08:12:31 +03:00
|
|
|
|
public ExtendedObservableCollection<VaultListPageModel.Folder> PresentationFolders { get; private set; }
|
|
|
|
|
= new ExtendedObservableCollection<VaultListPageModel.Folder>();
|
|
|
|
|
public ListView ListView { get; set; }
|
2016-08-18 04:19:19 +03:00
|
|
|
|
public VaultListPageModel.Site[] Sites { get; set; } = new VaultListPageModel.Site[] { };
|
|
|
|
|
public VaultListPageModel.Folder[] Folders { get; set; } = new VaultListPageModel.Folder[] { };
|
2016-07-12 02:36:39 +03:00
|
|
|
|
public SearchBar Search { get; set; }
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-05-04 02:49:49 +03:00
|
|
|
|
private void Init()
|
|
|
|
|
{
|
2016-07-15 08:52:33 +03:00
|
|
|
|
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted", (sender, success) =>
|
2016-07-01 03:08:34 +03:00
|
|
|
|
{
|
2016-07-12 06:55:16 +03:00
|
|
|
|
if(success)
|
|
|
|
|
{
|
2016-08-14 08:42:18 +03:00
|
|
|
|
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
2016-07-12 06:55:16 +03:00
|
|
|
|
}
|
2016-07-01 03:08:34 +03:00
|
|
|
|
});
|
|
|
|
|
|
2016-06-15 06:23:05 +03:00
|
|
|
|
if(!_favorites)
|
|
|
|
|
{
|
|
|
|
|
ToolbarItems.Add(new AddSiteToolBarItem(this));
|
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-08-14 04:43:15 +03:00
|
|
|
|
ListView = new ListView(ListViewCachingStrategy.RecycleElement)
|
2016-05-14 08:34:42 +03:00
|
|
|
|
{
|
|
|
|
|
IsGroupingEnabled = true,
|
2016-07-11 08:12:31 +03:00
|
|
|
|
ItemsSource = PresentationFolders,
|
2016-05-14 08:34:42 +03:00
|
|
|
|
HasUnevenRows = true,
|
2016-05-19 06:30:46 +03:00
|
|
|
|
GroupHeaderTemplate = new DataTemplate(() => new VaultListHeaderViewCell(this)),
|
2016-08-19 02:09:01 +03:00
|
|
|
|
ItemTemplate = new DataTemplate(() => new VaultListViewCell(this))
|
2016-05-14 08:34:42 +03:00
|
|
|
|
};
|
2016-06-29 07:34:20 +03:00
|
|
|
|
|
2016-06-18 01:14:24 +03:00
|
|
|
|
if(Device.OS == TargetPlatform.iOS)
|
|
|
|
|
{
|
2016-07-11 08:12:31 +03:00
|
|
|
|
ListView.RowHeight = -1;
|
2016-06-18 01:14:24 +03:00
|
|
|
|
}
|
2016-06-29 07:34:20 +03:00
|
|
|
|
|
2016-07-11 08:12:31 +03:00
|
|
|
|
ListView.ItemSelected += SiteSelected;
|
|
|
|
|
|
2016-07-12 02:36:39 +03:00
|
|
|
|
Search = new SearchBar
|
2016-07-11 08:12:31 +03:00
|
|
|
|
{
|
2016-07-12 06:55:16 +03:00
|
|
|
|
Placeholder = "Search vault",
|
2016-07-19 02:16:27 +03:00
|
|
|
|
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Button)),
|
|
|
|
|
CancelButtonColor = Color.FromHex("3c8dbc")
|
2016-07-11 08:12:31 +03:00
|
|
|
|
};
|
2016-07-12 02:36:39 +03:00
|
|
|
|
Search.TextChanged += SearchBar_TextChanged;
|
|
|
|
|
Search.SearchButtonPressed += SearchBar_SearchButtonPressed;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-06-15 06:23:05 +03:00
|
|
|
|
Title = _favorites ? AppResources.Favorites : AppResources.MyVault;
|
2016-07-11 08:12:31 +03:00
|
|
|
|
Content = new StackLayout
|
|
|
|
|
{
|
2016-07-12 02:36:39 +03:00
|
|
|
|
Children = { Search, ListView },
|
2016-07-11 08:12:31 +03:00
|
|
|
|
Spacing = 0
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SearchBar_SearchButtonPressed(object sender, EventArgs e)
|
|
|
|
|
{
|
2016-08-16 06:09:41 +03:00
|
|
|
|
_filterResultsCancellationTokenSource = FilterResultsBackground(((SearchBar)sender).Text,
|
|
|
|
|
_filterResultsCancellationTokenSource);
|
2016-07-11 08:12:31 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
var oldLength = e.OldTextValue?.Length ?? 0;
|
|
|
|
|
var newLength = e.NewTextValue?.Length ?? 0;
|
|
|
|
|
if(oldLength < 2 && newLength < 2 && oldLength < newLength)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 06:09:41 +03:00
|
|
|
|
_filterResultsCancellationTokenSource = FilterResultsBackground(e.NewTextValue,
|
|
|
|
|
_filterResultsCancellationTokenSource);
|
2016-07-11 08:12:31 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
private CancellationTokenSource FilterResultsBackground(string searchFilter, CancellationTokenSource previousCts)
|
2016-07-11 08:12:31 +03:00
|
|
|
|
{
|
2016-08-14 08:42:18 +03:00
|
|
|
|
var cts = new CancellationTokenSource();
|
2016-07-12 02:36:39 +03:00
|
|
|
|
Task.Run(async () =>
|
2016-07-11 08:12:31 +03:00
|
|
|
|
{
|
2016-07-12 06:55:16 +03:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(searchFilter))
|
2016-07-12 02:36:39 +03:00
|
|
|
|
{
|
2016-07-12 06:55:16 +03:00
|
|
|
|
await Task.Delay(300);
|
|
|
|
|
if(searchFilter != Search.Text)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2016-08-14 08:42:18 +03:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
previousCts?.Cancel();
|
|
|
|
|
}
|
2016-07-12 02:36:39 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
FilterResults(searchFilter, cts.Token);
|
|
|
|
|
}
|
|
|
|
|
catch(OperationCanceledException) { }
|
|
|
|
|
}, cts.Token);
|
|
|
|
|
|
|
|
|
|
return cts;
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
private void FilterResults(string searchFilter, CancellationToken ct)
|
2016-07-12 06:55:16 +03:00
|
|
|
|
{
|
2016-08-16 06:09:41 +03:00
|
|
|
|
ct.ThrowIfCancellationRequested();
|
2016-08-14 08:42:18 +03:00
|
|
|
|
|
2016-07-12 06:55:16 +03:00
|
|
|
|
if(string.IsNullOrWhiteSpace(searchFilter))
|
|
|
|
|
{
|
2016-08-14 08:42:18 +03:00
|
|
|
|
LoadFolders(Sites, ct);
|
2016-07-12 06:55:16 +03:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
searchFilter = searchFilter.ToLower();
|
2016-08-14 08:42:18 +03:00
|
|
|
|
var filteredSites = Sites
|
|
|
|
|
.Where(s => s.Name.ToLower().Contains(searchFilter) || s.Username.ToLower().Contains(searchFilter))
|
|
|
|
|
.TakeWhile(s => !ct.IsCancellationRequested)
|
2016-08-18 04:19:19 +03:00
|
|
|
|
.ToArray();
|
2016-08-14 08:42:18 +03:00
|
|
|
|
|
2016-08-16 06:09:41 +03:00
|
|
|
|
ct.ThrowIfCancellationRequested();
|
2016-08-14 08:42:18 +03:00
|
|
|
|
LoadFolders(filteredSites, ct);
|
2016-07-12 06:55:16 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-15 08:52:33 +03:00
|
|
|
|
protected override void OnAppearing()
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
|
|
|
|
base.OnAppearing();
|
2016-08-06 06:58:31 +03:00
|
|
|
|
if(_loadExistingData)
|
|
|
|
|
{
|
2016-08-14 08:42:18 +03:00
|
|
|
|
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
2016-08-06 06:58:31 +03:00
|
|
|
|
}
|
2016-06-28 07:55:53 +03:00
|
|
|
|
|
2016-07-02 01:54:00 +03:00
|
|
|
|
if(_connectivity.IsConnected && Device.OS == TargetPlatform.iOS && !_favorites)
|
2016-06-28 07:55:53 +03:00
|
|
|
|
{
|
2016-07-02 09:01:47 +03:00
|
|
|
|
var pushPromptShow = _settings.GetValueOrDefault<bool>(Constants.PushInitialPromptShown);
|
2016-07-26 06:34:19 +03:00
|
|
|
|
Action registerAction = () =>
|
|
|
|
|
{
|
|
|
|
|
var lastPushRegistration = _settings.GetValueOrDefault<DateTime?>(Constants.PushLastRegistrationDate);
|
2016-08-16 06:09:41 +03:00
|
|
|
|
if(!pushPromptShow || !lastPushRegistration.HasValue
|
|
|
|
|
|| (DateTime.UtcNow - lastPushRegistration) > TimeSpan.FromDays(1))
|
2016-07-26 06:34:19 +03:00
|
|
|
|
{
|
|
|
|
|
_pushNotification.Register();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-07-02 02:16:47 +03:00
|
|
|
|
if(!pushPromptShow)
|
2016-06-28 07:55:53 +03:00
|
|
|
|
{
|
2016-07-02 09:01:47 +03:00
|
|
|
|
_settings.AddOrUpdateValue(Constants.PushInitialPromptShown, true);
|
2016-07-26 06:34:19 +03:00
|
|
|
|
_userDialogs.Alert(new AlertConfig
|
|
|
|
|
{
|
|
|
|
|
Message = "bitwarden keeps your vault automatically synced by using push notifications."
|
2016-08-16 06:09:41 +03:00
|
|
|
|
+ " For the best possible experience, please select \"Ok\" on the following prompt when"
|
|
|
|
|
+ " asked to enable push notifications.",
|
2016-07-26 06:34:19 +03:00
|
|
|
|
Title = "Enable Automatic Syncing",
|
|
|
|
|
OnOk = registerAction,
|
|
|
|
|
OkText = "Ok, got it!"
|
|
|
|
|
});
|
2016-06-28 07:55:53 +03:00
|
|
|
|
}
|
2016-07-26 06:34:19 +03:00
|
|
|
|
else
|
2016-07-02 02:16:47 +03:00
|
|
|
|
{
|
2016-07-26 06:34:19 +03:00
|
|
|
|
// Check push registration once per day
|
|
|
|
|
registerAction();
|
2016-07-02 02:16:47 +03:00
|
|
|
|
}
|
2016-06-28 07:55:53 +03:00
|
|
|
|
}
|
2016-05-04 02:49:49 +03:00
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
private CancellationTokenSource FetchAndLoadVault()
|
2016-07-11 08:12:31 +03:00
|
|
|
|
{
|
2016-08-14 08:42:18 +03:00
|
|
|
|
var cts = new CancellationTokenSource();
|
2016-08-06 06:58:31 +03:00
|
|
|
|
_settings.AddOrUpdateValue(Constants.FirstVaultLoad, false);
|
|
|
|
|
_loadExistingData = true;
|
|
|
|
|
|
2016-07-12 06:55:16 +03:00
|
|
|
|
if(PresentationFolders.Count > 0 && _syncService.SyncInProgress)
|
|
|
|
|
{
|
2016-08-14 08:42:18 +03:00
|
|
|
|
return cts;
|
2016-07-12 06:55:16 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 06:09:41 +03:00
|
|
|
|
_filterResultsCancellationTokenSource?.Cancel();
|
|
|
|
|
|
2016-07-15 08:52:33 +03:00
|
|
|
|
Task.Run(async () =>
|
2016-07-12 02:36:39 +03:00
|
|
|
|
{
|
|
|
|
|
var foldersTask = _folderService.GetAllAsync();
|
|
|
|
|
var sitesTask = _favorites ? _siteService.GetAllAsync(true) : _siteService.GetAllAsync();
|
|
|
|
|
await Task.WhenAll(foldersTask, sitesTask);
|
2016-07-11 08:12:31 +03:00
|
|
|
|
|
2016-07-12 02:36:39 +03:00
|
|
|
|
var folders = await foldersTask;
|
|
|
|
|
var sites = await sitesTask;
|
2016-07-11 08:12:31 +03:00
|
|
|
|
|
2016-08-18 04:19:19 +03:00
|
|
|
|
Folders = folders
|
|
|
|
|
.Select(f => new VaultListPageModel.Folder(f))
|
|
|
|
|
.OrderBy(s => s.Name)
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
|
|
Sites = sites
|
|
|
|
|
.Select(s => new VaultListPageModel.Site(s))
|
|
|
|
|
.OrderBy(s => s.Name)
|
|
|
|
|
.ThenBy(s => s.Username)
|
|
|
|
|
.ToArray();
|
2016-07-11 08:12:31 +03:00
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
FilterResults(Search.Text, cts.Token);
|
|
|
|
|
}
|
|
|
|
|
catch(OperationCanceledException) { }
|
|
|
|
|
}, cts.Token);
|
|
|
|
|
|
|
|
|
|
return cts;
|
2016-07-11 08:12:31 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 04:19:19 +03:00
|
|
|
|
private void LoadFolders(VaultListPageModel.Site[] sites, CancellationToken ct)
|
2016-05-04 02:49:49 +03:00
|
|
|
|
{
|
2016-07-11 08:12:31 +03:00
|
|
|
|
var folders = new List<VaultListPageModel.Folder>(Folders);
|
|
|
|
|
|
|
|
|
|
foreach(var folder in folders)
|
|
|
|
|
{
|
|
|
|
|
if(folder.Any())
|
|
|
|
|
{
|
|
|
|
|
folder.Clear();
|
|
|
|
|
}
|
2016-08-14 08:42:18 +03:00
|
|
|
|
|
|
|
|
|
var sitesToAdd = sites
|
|
|
|
|
.Where(s => s.FolderId == folder.Id)
|
|
|
|
|
.TakeWhile(s => !ct.IsCancellationRequested)
|
|
|
|
|
.ToList();
|
|
|
|
|
|
2016-08-16 06:09:41 +03:00
|
|
|
|
ct.ThrowIfCancellationRequested();
|
2016-08-14 08:42:18 +03:00
|
|
|
|
folder.AddRange(sitesToAdd);
|
2016-07-11 08:12:31 +03:00
|
|
|
|
}
|
2016-05-04 02:49:49 +03:00
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
var noneToAdd = sites
|
|
|
|
|
.Where(s => s.FolderId == null)
|
|
|
|
|
.TakeWhile(s => !ct.IsCancellationRequested)
|
|
|
|
|
.ToList();
|
|
|
|
|
|
2016-08-16 06:09:41 +03:00
|
|
|
|
ct.ThrowIfCancellationRequested();
|
2016-08-14 08:42:18 +03:00
|
|
|
|
|
|
|
|
|
var noneFolder = new VaultListPageModel.Folder(noneToAdd);
|
2016-07-11 08:12:31 +03:00
|
|
|
|
folders.Add(noneFolder);
|
2016-05-19 03:29:03 +03:00
|
|
|
|
|
2016-08-14 08:42:18 +03:00
|
|
|
|
var foldersToAdd = folders
|
|
|
|
|
.Where(f => f.Any())
|
|
|
|
|
.TakeWhile(s => !ct.IsCancellationRequested)
|
|
|
|
|
.ToList();
|
|
|
|
|
|
2016-08-16 06:09:41 +03:00
|
|
|
|
ct.ThrowIfCancellationRequested();
|
|
|
|
|
Device.BeginInvokeOnMainThread(() => PresentationFolders.ResetWithRange(foldersToAdd));
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-05-04 02:49:49 +03:00
|
|
|
|
private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
2016-05-08 06:11:47 +03:00
|
|
|
|
var site = e.SelectedItem as VaultListPageModel.Site;
|
2016-05-13 07:11:32 +03:00
|
|
|
|
var page = new ExtendedNavigationPage(new VaultViewSitePage(site.Id));
|
|
|
|
|
Navigation.PushModalAsync(page);
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-16 07:09:46 +03:00
|
|
|
|
private async void MoreClickedAsync(VaultListPageModel.Site site)
|
2016-05-02 09:52:09 +03:00
|
|
|
|
{
|
2016-07-07 05:59:13 +03:00
|
|
|
|
var buttons = new List<string> { AppResources.View, AppResources.Edit };
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(site.Password.Value))
|
|
|
|
|
{
|
|
|
|
|
buttons.Add(AppResources.CopyPassword);
|
|
|
|
|
}
|
|
|
|
|
if(!string.IsNullOrWhiteSpace(site.Username))
|
|
|
|
|
{
|
|
|
|
|
buttons.Add(AppResources.CopyUsername);
|
|
|
|
|
}
|
2016-08-16 06:09:41 +03:00
|
|
|
|
if(!string.IsNullOrWhiteSpace(site.Uri.Value) && (site.Uri.Value.StartsWith("http://")
|
|
|
|
|
|| site.Uri.Value.StartsWith("https://")))
|
2016-07-07 05:59:13 +03:00
|
|
|
|
{
|
|
|
|
|
buttons.Add(AppResources.GoToWebsite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var selection = await DisplayActionSheet(site.Name, AppResources.Cancel, null, buttons.ToArray());
|
2016-05-02 09:52:09 +03:00
|
|
|
|
|
2016-05-07 20:42:09 +03:00
|
|
|
|
if(selection == AppResources.View)
|
2016-05-04 02:49:49 +03:00
|
|
|
|
{
|
2016-05-13 07:11:32 +03:00
|
|
|
|
var page = new ExtendedNavigationPage(new VaultViewSitePage(site.Id));
|
|
|
|
|
await Navigation.PushModalAsync(page);
|
2016-05-04 02:49:49 +03:00
|
|
|
|
}
|
2016-05-07 20:42:09 +03:00
|
|
|
|
else if(selection == AppResources.Edit)
|
|
|
|
|
{
|
2016-05-13 07:11:32 +03:00
|
|
|
|
var page = new ExtendedNavigationPage(new VaultEditSitePage(site.Id));
|
|
|
|
|
await Navigation.PushModalAsync(page);
|
2016-05-07 20:42:09 +03:00
|
|
|
|
}
|
|
|
|
|
else if(selection == AppResources.CopyPassword)
|
|
|
|
|
{
|
2016-07-07 05:59:13 +03:00
|
|
|
|
Copy(site.Password.Value, AppResources.Password);
|
2016-05-07 20:42:09 +03:00
|
|
|
|
}
|
|
|
|
|
else if(selection == AppResources.CopyUsername)
|
|
|
|
|
{
|
|
|
|
|
Copy(site.Username, AppResources.Username);
|
|
|
|
|
}
|
|
|
|
|
else if(selection == AppResources.GoToWebsite)
|
|
|
|
|
{
|
2016-07-07 05:59:13 +03:00
|
|
|
|
Device.OpenUri(new Uri(site.Uri.Value));
|
2016-05-07 20:42:09 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Copy(string copyText, string alertLabel)
|
|
|
|
|
{
|
|
|
|
|
_clipboardService.CopyToClipboard(copyText);
|
2016-07-26 07:38:41 +03:00
|
|
|
|
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
|
2016-05-04 02:49:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class AddSiteToolBarItem : ToolbarItem
|
|
|
|
|
{
|
2016-05-18 06:09:20 +03:00
|
|
|
|
private readonly VaultListSitesPage _page;
|
2016-05-04 02:49:49 +03:00
|
|
|
|
|
2016-05-18 06:09:20 +03:00
|
|
|
|
public AddSiteToolBarItem(VaultListSitesPage page)
|
2016-05-04 02:49:49 +03:00
|
|
|
|
{
|
|
|
|
|
_page = page;
|
2016-05-07 20:42:09 +03:00
|
|
|
|
Text = AppResources.Add;
|
2016-06-14 05:09:16 +03:00
|
|
|
|
Icon = "plus";
|
2016-05-04 02:49:49 +03:00
|
|
|
|
Clicked += ClickedItem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void ClickedItem(object sender, EventArgs e)
|
|
|
|
|
{
|
2016-05-13 07:11:32 +03:00
|
|
|
|
var page = new ExtendedNavigationPage(new VaultAddSitePage());
|
|
|
|
|
await _page.Navigation.PushModalAsync(page);
|
2016-05-04 02:49:49 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-29 06:44:47 +03:00
|
|
|
|
private class VaultListViewCell : LabeledDetailCell
|
2016-05-04 02:49:49 +03:00
|
|
|
|
{
|
2016-06-15 07:36:50 +03:00
|
|
|
|
private VaultListSitesPage _page;
|
|
|
|
|
|
2016-07-02 02:16:47 +03:00
|
|
|
|
public static readonly BindableProperty SiteParameterProperty = BindableProperty.Create(nameof(SiteParameter),
|
2016-06-29 07:34:20 +03:00
|
|
|
|
typeof(VaultListPageModel.Site), typeof(VaultListViewCell), null);
|
|
|
|
|
|
2016-05-18 06:09:20 +03:00
|
|
|
|
public VaultListViewCell(VaultListSitesPage page)
|
2016-05-04 02:49:49 +03:00
|
|
|
|
{
|
2016-06-15 07:36:50 +03:00
|
|
|
|
_page = page;
|
2016-05-06 07:17:38 +03:00
|
|
|
|
|
2016-06-29 07:34:20 +03:00
|
|
|
|
SetBinding(SiteParameterProperty, new Binding("."));
|
2016-06-29 06:44:47 +03:00
|
|
|
|
Label.SetBinding<VaultListPageModel.Site>(Label.TextProperty, s => s.Name);
|
|
|
|
|
Detail.SetBinding<VaultListPageModel.Site>(Label.TextProperty, s => s.Username);
|
2016-06-16 07:09:46 +03:00
|
|
|
|
|
2016-07-01 01:53:43 +03:00
|
|
|
|
Button.Image = "more";
|
|
|
|
|
Button.Command = new Command(() => ShowMore());
|
2016-07-01 02:08:09 +03:00
|
|
|
|
Button.BackgroundColor = Color.Transparent;
|
2016-08-19 02:09:01 +03:00
|
|
|
|
|
|
|
|
|
BackgroundColor = Color.White;
|
2016-06-15 07:36:50 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-29 07:34:20 +03:00
|
|
|
|
public VaultListPageModel.Site SiteParameter
|
|
|
|
|
{
|
|
|
|
|
get { return GetValue(SiteParameterProperty) as VaultListPageModel.Site; }
|
|
|
|
|
set { SetValue(SiteParameterProperty, value); }
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-01 01:53:43 +03:00
|
|
|
|
private void ShowMore()
|
2016-06-15 07:36:50 +03:00
|
|
|
|
{
|
2016-07-01 01:53:43 +03:00
|
|
|
|
_page.MoreClickedAsync(SiteParameter);
|
2016-05-14 08:34:42 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-01 02:08:09 +03:00
|
|
|
|
private class VaultListHeaderViewCell : ExtendedViewCell
|
2016-05-14 08:34:42 +03:00
|
|
|
|
{
|
2016-05-18 06:09:20 +03:00
|
|
|
|
public VaultListHeaderViewCell(VaultListSitesPage page)
|
2016-05-14 08:34:42 +03:00
|
|
|
|
{
|
|
|
|
|
var image = new Image
|
|
|
|
|
{
|
2016-07-30 07:46:17 +03:00
|
|
|
|
Source = "folder",
|
2016-05-17 05:47:36 +03:00
|
|
|
|
VerticalOptions = LayoutOptions.CenterAndExpand
|
2016-05-14 08:34:42 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var label = new Label
|
|
|
|
|
{
|
2016-05-17 05:47:36 +03:00
|
|
|
|
VerticalTextAlignment = TextAlignment.Center,
|
2016-05-25 03:14:37 +03:00
|
|
|
|
VerticalOptions = LayoutOptions.CenterAndExpand,
|
2016-06-17 07:01:25 +03:00
|
|
|
|
Style = (Style)Application.Current.Resources["text-muted"]
|
2016-05-14 08:34:42 +03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
label.SetBinding<VaultListPageModel.Folder>(Label.TextProperty, s => s.Name);
|
|
|
|
|
|
|
|
|
|
var stackLayout = new StackLayout
|
|
|
|
|
{
|
|
|
|
|
Orientation = StackOrientation.Horizontal,
|
2016-05-25 03:14:37 +03:00
|
|
|
|
VerticalOptions = LayoutOptions.FillAndExpand,
|
2016-06-28 03:56:59 +03:00
|
|
|
|
Children = { image, label },
|
2016-06-29 07:34:20 +03:00
|
|
|
|
Padding = new Thickness(16, 0, 0, 0)
|
2016-05-14 08:34:42 +03:00
|
|
|
|
};
|
2016-06-15 05:19:40 +03:00
|
|
|
|
|
2016-05-25 03:14:37 +03:00
|
|
|
|
View = stackLayout;
|
2016-07-01 01:53:43 +03:00
|
|
|
|
Height = 40;
|
2016-07-01 02:08:09 +03:00
|
|
|
|
BackgroundColor = Color.FromHex("efeff4");
|
2016-05-04 02:49:49 +03:00
|
|
|
|
}
|
2016-05-02 09:52:09 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|