diff --git a/src/iOS.Autofill/LoginListViewController.cs b/src/iOS.Autofill/LoginListViewController.cs index 2935bc5dd..01456e672 100644 --- a/src/iOS.Autofill/LoginListViewController.cs +++ b/src/iOS.Autofill/LoginListViewController.cs @@ -1,12 +1,11 @@ using System; -using System.Linq; using Bit.iOS.Autofill.Models; using Foundation; using UIKit; -using Bit.iOS.Core.Utilities; using Bit.iOS.Core.Controllers; using Bit.App.Resources; using Bit.iOS.Core.Views; +using Bit.iOS.Autofill.Utilities; namespace Bit.iOS.Autofill { @@ -87,7 +86,7 @@ namespace Bit.iOS.Autofill private LoginListViewController _controller; public TableSource(LoginListViewController controller) - :base(controller.Context, controller) + : base(controller.Context, controller) { _context = controller.Context; _controller = controller; @@ -95,77 +94,8 @@ namespace Bit.iOS.Autofill public override void RowSelected(UITableView tableView, NSIndexPath indexPath) { - tableView.DeselectRow(indexPath, true); - tableView.EndEditing(true); - - if(_tableItems == null || _tableItems.Count() == 0) - { - _controller.PerformSegue("loginAddSegue", this); - return; - } - - var item = _tableItems.ElementAt(indexPath.Row); - if(item == null) - { - _controller.CPViewController.CompleteRequest(null, null, null); - return; - } - - if(!string.IsNullOrWhiteSpace(item.Password)) - { - string totp = null; - if(!_settings.GetValueOrDefault(App.Constants.SettingDisableTotpCopy, false)) - { - totp = GetTotp(item); - } - - _controller.CPViewController.CompleteRequest(item.Username, item.Password, totp); - } - else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Totp.Value)) - { - var sheet = Dialogs.CreateActionSheet(item.Name, _controller); - if(!string.IsNullOrWhiteSpace(item.Username)) - { - sheet.AddAction(UIAlertAction.Create(AppResources.CopyUsername, UIAlertActionStyle.Default, a => - { - UIPasteboard clipboard = UIPasteboard.General; - clipboard.String = item.Username; - var alert = Dialogs.CreateMessageAlert(AppResources.CopyUsername); - _controller.PresentViewController(alert, true, () => - { - _controller.DismissViewController(true, null); - }); - })); - } - - if(!string.IsNullOrWhiteSpace(item.Totp.Value)) - { - sheet.AddAction(UIAlertAction.Create(AppResources.CopyTotp, UIAlertActionStyle.Default, a => - { - var totp = GetTotp(item); - if(string.IsNullOrWhiteSpace(totp)) - { - return; - } - - UIPasteboard clipboard = UIPasteboard.General; - clipboard.String = totp; - var alert = Dialogs.CreateMessageAlert(AppResources.CopiedTotp); - _controller.PresentViewController(alert, true, () => - { - _controller.DismissViewController(true, null); - }); - })); - } - - sheet.AddAction(UIAlertAction.Create(AppResources.Cancel, UIAlertActionStyle.Cancel, null)); - _controller.PresentViewController(sheet, true, null); - } - else - { - var alert = Dialogs.CreateAlert(null, AppResources.NoUsernamePasswordConfigured, AppResources.Ok); - _controller.PresentViewController(alert, true, null); - } + AutofillHelpers.TableRowSelected(tableView, indexPath, this, + _controller.CPViewController, _controller, _settings, "loginAddSegue"); } } } diff --git a/src/iOS.Autofill/LoginSearchViewController.cs b/src/iOS.Autofill/LoginSearchViewController.cs index 8bcc35a09..59ec6506d 100644 --- a/src/iOS.Autofill/LoginSearchViewController.cs +++ b/src/iOS.Autofill/LoginSearchViewController.cs @@ -1,14 +1,11 @@ using System; -using System.Linq; using Bit.iOS.Autofill.Models; using Foundation; using UIKit; -using Bit.iOS.Core.Utilities; using Bit.iOS.Core.Controllers; using Bit.App.Resources; using Bit.iOS.Core.Views; -using System.Threading; -using System.Threading.Tasks; +using Bit.iOS.Autofill.Utilities; namespace Bit.iOS.Autofill { @@ -36,7 +33,7 @@ namespace Bit.iOS.Autofill TableView.RowHeight = UITableView.AutomaticDimension; TableView.EstimatedRowHeight = 44; TableView.Source = new TableSource(this); - SearchBar.Delegate = new SearchDelegate(this); + SearchBar.Delegate = new ExtensionSearchDelegate(TableView); await ((TableSource)TableView.Source).LoadItemsAsync(false, SearchBar.Text); } @@ -87,118 +84,8 @@ namespace Bit.iOS.Autofill public override void RowSelected(UITableView tableView, NSIndexPath indexPath) { - tableView.DeselectRow(indexPath, true); - tableView.EndEditing(true); - - if(_tableItems == null || _tableItems.Count() == 0) - { - _controller.PerformSegue("loginAddFromSearchSegue", this); - return; - } - - var item = _tableItems.ElementAt(indexPath.Row); - if(item == null) - { - _controller.CPViewController.CompleteRequest(null, null, null); - return; - } - - if(!string.IsNullOrWhiteSpace(item.Password)) - { - string totp = null; - if(!_settings.GetValueOrDefault(App.Constants.SettingDisableTotpCopy, false)) - { - totp = GetTotp(item); - } - - _controller.CPViewController.CompleteRequest(item.Username, item.Password, totp); - } - else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Totp.Value)) - { - var sheet = Dialogs.CreateActionSheet(item.Name, _controller); - if(!string.IsNullOrWhiteSpace(item.Username)) - { - sheet.AddAction(UIAlertAction.Create(AppResources.CopyUsername, UIAlertActionStyle.Default, a => - { - UIPasteboard clipboard = UIPasteboard.General; - clipboard.String = item.Username; - var alert = Dialogs.CreateMessageAlert(AppResources.CopyUsername); - _controller.PresentViewController(alert, true, () => - { - _controller.DismissViewController(true, null); - }); - })); - } - - if(!string.IsNullOrWhiteSpace(item.Totp.Value)) - { - sheet.AddAction(UIAlertAction.Create(AppResources.CopyTotp, UIAlertActionStyle.Default, a => - { - var totp = GetTotp(item); - if(string.IsNullOrWhiteSpace(totp)) - { - return; - } - - UIPasteboard clipboard = UIPasteboard.General; - clipboard.String = totp; - var alert = Dialogs.CreateMessageAlert(AppResources.CopiedTotp); - _controller.PresentViewController(alert, true, () => - { - _controller.DismissViewController(true, null); - }); - })); - } - - sheet.AddAction(UIAlertAction.Create(AppResources.Cancel, UIAlertActionStyle.Cancel, null)); - _controller.PresentViewController(sheet, true, null); - } - else - { - var alert = Dialogs.CreateAlert(null, AppResources.NoUsernamePasswordConfigured, AppResources.Ok); - _controller.PresentViewController(alert, true, null); - } - } - } - - public class SearchDelegate : UISearchBarDelegate - { - private readonly LoginSearchViewController _controller; - private CancellationTokenSource _filterResultsCancellationTokenSource; - - public SearchDelegate(LoginSearchViewController controller) - { - _controller = controller; - } - - public override void TextChanged(UISearchBar searchBar, string searchText) - { - var cts = new CancellationTokenSource(); - Task.Run(() => - { - NSRunLoop.Main.BeginInvokeOnMainThread(async () => - { - if (!string.IsNullOrWhiteSpace(searchText)) - { - await Task.Delay(300); - if (searchText != searchBar.Text) - { - return; - } - else - { - _filterResultsCancellationTokenSource?.Cancel(); - } - } - try - { - ((TableSource)_controller.TableView.Source).FilterResults(searchText, cts.Token); - _controller.TableView.ReloadData(); - } - catch (OperationCanceledException) { } - _filterResultsCancellationTokenSource = cts; - }); - }, cts.Token); + AutofillHelpers.TableRowSelected(tableView, indexPath, this, + _controller.CPViewController, _controller, _settings, "loginAddFromSearchSegue"); } } } diff --git a/src/iOS.Autofill/Utilities/AutofillHelpers.cs b/src/iOS.Autofill/Utilities/AutofillHelpers.cs new file mode 100644 index 000000000..a56964841 --- /dev/null +++ b/src/iOS.Autofill/Utilities/AutofillHelpers.cs @@ -0,0 +1,91 @@ +using System; +using System.Linq; +using Bit.App.Resources; +using Bit.iOS.Core.Utilities; +using Bit.iOS.Core.Views; +using Foundation; +using Plugin.Settings.Abstractions; +using UIKit; + +namespace Bit.iOS.Autofill.Utilities +{ + public static class AutofillHelpers + { + public static void TableRowSelected(UITableView tableView, NSIndexPath indexPath, + ExtensionTableSource tableSource, CredentialProviderViewController cpViewController, + UITableViewController controller, ISettings settings, string loginAddSegue) + { + tableView.DeselectRow(indexPath, true); + tableView.EndEditing(true); + + if(tableSource.Items == null || tableSource.Items.Count() == 0) + { + controller.PerformSegue(loginAddSegue, tableSource); + return; + } + + var item = tableSource.Items.ElementAt(indexPath.Row); + if(item == null) + { + cpViewController.CompleteRequest(null); + return; + } + + if(!string.IsNullOrWhiteSpace(item.Password)) + { + string totp = null; + if(!settings.GetValueOrDefault(App.Constants.SettingDisableTotpCopy, false)) + { + totp = tableSource.GetTotp(item); + } + + cpViewController.CompleteRequest(item.Username, item.Password, totp); + } + else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Totp.Value)) + { + var sheet = Dialogs.CreateActionSheet(item.Name, controller); + if(!string.IsNullOrWhiteSpace(item.Username)) + { + sheet.AddAction(UIAlertAction.Create(AppResources.CopyUsername, UIAlertActionStyle.Default, a => + { + UIPasteboard clipboard = UIPasteboard.General; + clipboard.String = item.Username; + var alert = Dialogs.CreateMessageAlert(AppResources.CopyUsername); + controller.PresentViewController(alert, true, () => + { + controller.DismissViewController(true, null); + }); + })); + } + + if(!string.IsNullOrWhiteSpace(item.Totp.Value)) + { + sheet.AddAction(UIAlertAction.Create(AppResources.CopyTotp, UIAlertActionStyle.Default, a => + { + var totp = tableSource.GetTotp(item); + if(string.IsNullOrWhiteSpace(totp)) + { + return; + } + + UIPasteboard clipboard = UIPasteboard.General; + clipboard.String = totp; + var alert = Dialogs.CreateMessageAlert(AppResources.CopiedTotp); + controller.PresentViewController(alert, true, () => + { + controller.DismissViewController(true, null); + }); + })); + } + + sheet.AddAction(UIAlertAction.Create(AppResources.Cancel, UIAlertActionStyle.Cancel, null)); + controller.PresentViewController(sheet, true, null); + } + else + { + var alert = Dialogs.CreateAlert(null, AppResources.NoUsernamePasswordConfigured, AppResources.Ok); + controller.PresentViewController(alert, true, null); + } + } + } +} \ No newline at end of file diff --git a/src/iOS.Autofill/iOS.Autofill.csproj b/src/iOS.Autofill/iOS.Autofill.csproj index e508cc3f6..701d7b25b 100644 --- a/src/iOS.Autofill/iOS.Autofill.csproj +++ b/src/iOS.Autofill/iOS.Autofill.csproj @@ -213,6 +213,7 @@ SetupViewController.cs + @@ -299,5 +300,6 @@ + \ No newline at end of file diff --git a/src/iOS.Core/Views/ExtensionSearchDelegate.cs b/src/iOS.Core/Views/ExtensionSearchDelegate.cs new file mode 100644 index 000000000..317d55138 --- /dev/null +++ b/src/iOS.Core/Views/ExtensionSearchDelegate.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Foundation; +using UIKit; + +namespace Bit.iOS.Core.Views +{ + public class ExtensionSearchDelegate : UISearchBarDelegate + { + private readonly UITableView _tableView; + private CancellationTokenSource _filterResultsCancellationTokenSource; + + public ExtensionSearchDelegate(UITableView tableView) + { + _tableView = tableView; + } + + public override void TextChanged(UISearchBar searchBar, string searchText) + { + var cts = new CancellationTokenSource(); + Task.Run(() => + { + NSRunLoop.Main.BeginInvokeOnMainThread(async () => + { + if(!string.IsNullOrWhiteSpace(searchText)) + { + await Task.Delay(300); + if(searchText != searchBar.Text) + { + return; + } + else + { + _filterResultsCancellationTokenSource?.Cancel(); + } + } + try + { + ((ExtensionTableSource)_tableView.Source).FilterResults(searchText, cts.Token); + _tableView.ReloadData(); + } + catch(OperationCanceledException) { } + _filterResultsCancellationTokenSource = cts; + }); + }, cts.Token); + } + } +} \ No newline at end of file diff --git a/src/iOS.Core/Views/ExtensionTableSource.cs b/src/iOS.Core/Views/ExtensionTableSource.cs index 5eeca6abf..d9102d664 100644 --- a/src/iOS.Core/Views/ExtensionTableSource.cs +++ b/src/iOS.Core/Views/ExtensionTableSource.cs @@ -21,7 +21,6 @@ namespace Bit.iOS.Core.Views private const string CellIdentifier = "TableCell"; private IEnumerable _allItems = new List(); - protected IEnumerable _tableItems = new List(); protected ICipherService _cipherService; protected ISettings _settings; private bool _accessPremium; @@ -37,6 +36,8 @@ namespace Bit.iOS.Core.Views _controller = controller; } + public IEnumerable Items { get; private set; } + public async Task LoadItemsAsync(bool urlFilter = true, string searchFilter = null) { var combinedLogins = new List(); @@ -74,12 +75,12 @@ namespace Bit.iOS.Core.Views if(string.IsNullOrWhiteSpace(searchFilter)) { - _tableItems = _allItems.ToList(); + Items = _allItems.ToList(); } else { searchFilter = searchFilter.ToLower(); - _tableItems = _allItems + Items = _allItems .Where(s => s.Name.ToLower().Contains(searchFilter) || (s.Username?.ToLower().Contains(searchFilter) ?? false) || (s.Uris?.FirstOrDefault()?.Uri.ToLower().Contains(searchFilter) ?? false)) @@ -92,12 +93,12 @@ namespace Bit.iOS.Core.Views public override nint RowsInSection(UITableView tableview, nint section) { - return _tableItems == null || _tableItems.Count() == 0 ? 1 : _tableItems.Count(); + return Items == null || Items.Count() == 0 ? 1 : Items.Count(); } public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) { - if(_tableItems == null || _tableItems.Count() == 0) + if(Items == null || Items.Count() == 0) { var noDataCell = new UITableViewCell(UITableViewCellStyle.Default, "NoDataCell"); noDataCell.TextLabel.Text = AppResources.NoItemsTap; @@ -121,17 +122,17 @@ namespace Bit.iOS.Core.Views public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath) { - if(_tableItems == null || _tableItems.Count() == 0 || cell == null) + if(Items == null || Items.Count() == 0 || cell == null) { return; } - var item = _tableItems.ElementAt(indexPath.Row); + var item = Items.ElementAt(indexPath.Row); cell.TextLabel.Text = item.Name; cell.DetailTextLabel.Text = item.Username; } - protected string GetTotp(CipherViewModel item) + public string GetTotp(CipherViewModel item) { string totp = null; if(_accessPremium) diff --git a/src/iOS.Core/iOS.Core.csproj b/src/iOS.Core/iOS.Core.csproj index da54de2ca..ba09d23f4 100644 --- a/src/iOS.Core/iOS.Core.csproj +++ b/src/iOS.Core/iOS.Core.csproj @@ -71,6 +71,7 @@ + diff --git a/src/iOS.Extension/LoginListViewController.cs b/src/iOS.Extension/LoginListViewController.cs index a7fec16aa..b332e51cc 100644 --- a/src/iOS.Extension/LoginListViewController.cs +++ b/src/iOS.Extension/LoginListViewController.cs @@ -107,13 +107,13 @@ namespace Bit.iOS.Extension tableView.DeselectRow(indexPath, true); tableView.EndEditing(true); - if(_tableItems == null || _tableItems.Count() == 0) + if(Items == null || Items.Count() == 0) { _controller.PerformSegue("loginAddSegue", this); return; } - var item = _tableItems.ElementAt(indexPath.Row); + var item = Items.ElementAt(indexPath.Row); if(item == null) { _controller.LoadingController.CompleteRequest(null);