2016-05-02 09:52:09 +03:00
using System ;
using System.Collections.ObjectModel ;
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-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-05-07 20:42:09 +03:00
private readonly IClipboardService _clipboardService ;
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-05-02 09:52:09 +03:00
2016-06-15 06:23:05 +03:00
public VaultListSitesPage ( bool favorites )
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-05-04 02:49:49 +03:00
_userDialogs = Resolver . Resolve < IUserDialogs > ( ) ;
2016-05-07 20:42:09 +03:00
_clipboardService = Resolver . Resolve < IClipboardService > ( ) ;
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-05-04 02:49:49 +03:00
Init ( ) ;
}
2016-05-03 01:35:01 +03:00
2016-05-19 03:29:03 +03:00
public ExtendedObservableCollection < VaultListPageModel . Folder > Folders { get ; private set ; } = new ExtendedObservableCollection < VaultListPageModel . Folder > ( ) ;
2016-05-02 09:52:09 +03:00
2016-05-04 02:49:49 +03:00
private void Init ( )
{
2016-06-15 06:23:05 +03:00
if ( ! _favorites )
{
ToolbarItems . Add ( new AddSiteToolBarItem ( this ) ) ;
}
2016-05-02 09:52:09 +03:00
2016-05-14 08:34:42 +03:00
var listView = new ListView
{
IsGroupingEnabled = true ,
ItemsSource = Folders ,
HasUnevenRows = true ,
2016-05-19 06:30:46 +03:00
GroupHeaderTemplate = new DataTemplate ( ( ) = > new VaultListHeaderViewCell ( this ) ) ,
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-06-29 07:34:20 +03:00
listView . RowHeight = - 1 ;
2016-06-18 01:14:24 +03:00
}
2016-06-29 07:34:20 +03:00
2016-05-04 02:49:49 +03:00
listView . ItemSelected + = SiteSelected ;
2016-05-02 09:52:09 +03:00
2016-06-15 06:23:05 +03:00
Title = _favorites ? AppResources . Favorites : AppResources . MyVault ;
2016-05-04 02:49:49 +03:00
Content = listView ;
2016-05-02 09:52:09 +03:00
}
2016-06-28 07:55:53 +03:00
protected async override void OnAppearing ( )
2016-05-02 09:52:09 +03:00
{
base . OnAppearing ( ) ;
2016-05-04 02:49:49 +03:00
LoadFoldersAsync ( ) . Wait ( ) ;
2016-06-28 07:55:53 +03:00
if ( Device . OS = = TargetPlatform . iOS & & ! _favorites )
{
if ( ! _settings . GetValueOrDefault < bool > ( Constants . PushPromptShown ) )
{
_settings . AddOrUpdateValue ( Constants . PushPromptShown , true ) ;
await _userDialogs . AlertAsync ( "bitwarden keeps your vault automatically synced by using push notifications. For the best possible experience, please select \"Ok\" on the following prompt when asked to enable push notifications." , "Enable Automatic Syncing" , "Ok, got it!" ) ;
}
_pushNotification . Register ( ) ;
}
2016-05-04 02:49:49 +03:00
}
2016-05-02 09:52:09 +03:00
2016-05-04 02:49:49 +03:00
private async Task LoadFoldersAsync ( )
{
var folders = await _folderService . GetAllAsync ( ) ;
2016-06-15 06:23:05 +03:00
var sites = _favorites ? await _siteService . GetAllAsync ( true ) : await _siteService . GetAllAsync ( ) ;
2016-05-04 02:49:49 +03:00
2016-05-19 03:29:03 +03:00
var pageFolders = folders . Select ( f = > new VaultListPageModel . Folder ( f , sites . Where ( s = > s . FolderId = = f . Id ) ) ) . ToList ( ) ;
2016-05-08 06:11:47 +03:00
var noneFolder = new VaultListPageModel . Folder ( sites . Where ( s = > s . FolderId = = null ) ) ;
2016-05-19 03:29:03 +03:00
pageFolders . Add ( noneFolder ) ;
2016-06-15 05:19:40 +03:00
Folders . ResetWithRange ( pageFolders . Where ( f = > f . Any ( ) ) ) ;
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-06-16 07:09:46 +03:00
var selection = await DisplayActionSheet ( site . Name , AppResources . Cancel , null ,
2016-05-07 20:42:09 +03:00
AppResources . View , AppResources . Edit , AppResources . CopyPassword , AppResources . CopyUsername , AppResources . GoToWebsite ) ;
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 )
{
Copy ( site . Password , AppResources . Password ) ;
}
else if ( selection = = AppResources . CopyUsername )
{
Copy ( site . Username , AppResources . Username ) ;
}
else if ( selection = = AppResources . GoToWebsite )
{
Device . OpenUri ( new Uri ( site . Uri ) ) ;
}
}
private void Copy ( string copyText , string alertLabel )
{
_clipboardService . CopyToClipboard ( copyText ) ;
_userDialogs . SuccessToast ( string . Format ( AppResources . ValueHasBeenCopied , alertLabel ) ) ;
2016-05-04 02:49:49 +03:00
}
private async void DeleteClickedAsync ( object sender , EventArgs e )
{
2016-05-07 20:42:09 +03:00
if ( ! await _userDialogs . ConfirmAsync ( AppResources . DoYouReallyWantToDelete , null , AppResources . Yes , AppResources . No ) )
{
return ;
}
2016-05-04 02:49:49 +03:00
var mi = sender as MenuItem ;
2016-05-08 06:11:47 +03:00
var site = mi . CommandParameter as VaultListPageModel . Site ;
2016-05-04 02:49:49 +03:00
var deleteCall = await _siteService . DeleteAsync ( site . Id ) ;
if ( deleteCall . Succeeded )
{
var folder = Folders . Single ( f = > f . Id = = site . FolderId ) ;
var siteIndex = folder . Select ( ( s , i ) = > new { s , i } ) . First ( s = > s . s . Id = = site . Id ) . i ;
folder . RemoveAt ( siteIndex ) ;
2016-05-07 20:42:09 +03:00
_userDialogs . SuccessToast ( AppResources . SiteDeleted ) ;
2016-05-04 02:49:49 +03:00
}
else if ( deleteCall . Errors . Count ( ) > 0 )
{
2016-05-07 20:42:09 +03:00
await DisplayAlert ( AppResources . AnErrorHasOccurred , deleteCall . Errors . First ( ) . Message , AppResources . Ok ) ;
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-06-29 07:34:20 +03:00
public static readonly BindableProperty SiteParameterProperty = BindableProperty . Create ( nameof ( SiteParameter ) ,
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-16 07:09:46 +03:00
// Adding whitespace to Delete action to account for the negative margin offset on the listview
2016-07-01 01:53:43 +03:00
var deleteAction = new MenuItem { Text = AppResources . Delete , IsDestructive = true } ;
2016-05-06 07:17:38 +03:00
deleteAction . SetBinding ( MenuItem . CommandParameterProperty , new Binding ( "." ) ) ;
deleteAction . Clicked + = page . DeleteClickedAsync ;
2016-06-16 07:09:46 +03:00
var moreAction = new MenuItem { Text = AppResources . More } ;
moreAction . SetBinding ( MenuItem . CommandParameterProperty , new Binding ( "." ) ) ;
moreAction . Clicked + = MoreAction_Clicked ;
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-05-06 07:17:38 +03:00
ContextActions . Add ( deleteAction ) ;
2016-06-16 07:09:46 +03:00
ContextActions . Add ( moreAction ) ;
2016-05-14 08:34:42 +03:00
2016-07-01 01:53:43 +03:00
Button . Image = "more" ;
Button . Command = new Command ( ( ) = > ShowMore ( ) ) ;
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-06-16 07:09:46 +03:00
private void MoreAction_Clicked ( object sender , EventArgs e )
{
var menuItem = sender as MenuItem ;
var site = menuItem . CommandParameter as VaultListPageModel . Site ;
_page . MoreClickedAsync ( site ) ;
}
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
}
}
private class VaultListHeaderViewCell : ViewCell
{
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-05-17 05:47:36 +03:00
Source = "fa_folder_open.png" ,
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
BackgroundColor = Color . FromHex ( "efeff4" ) ,
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-05-04 02:49:49 +03:00
}
2016-05-02 09:52:09 +03:00
}
}
}