Moved add/edit pages to use custom form cells. Moved navigation of vault to modals. Created custom renderer for left modal dismiss button on navigation pages. refresh for edit site UI.

This commit is contained in:
Kyle Spearrin 2016-05-13 00:11:32 -04:00
parent 8ec957c39c
commit 83f308cbf0
13 changed files with 340 additions and 103 deletions

View file

@ -44,12 +44,17 @@
<Compile Include="Behaviors\EmailValidationBehavior.cs" /> <Compile Include="Behaviors\EmailValidationBehavior.cs" />
<Compile Include="Behaviors\ConnectivityBehavior.cs" /> <Compile Include="Behaviors\ConnectivityBehavior.cs" />
<Compile Include="Behaviors\RequiredValidationBehavior.cs" /> <Compile Include="Behaviors\RequiredValidationBehavior.cs" />
<Compile Include="Controls\DismissModalToolBarItem.cs" />
<Compile Include="Controls\EntryLabel.cs" /> <Compile Include="Controls\EntryLabel.cs" />
<Compile Include="Controls\ExtendedEditor.cs" /> <Compile Include="Controls\ExtendedEditor.cs" />
<Compile Include="Controls\ExtendedNavigationPage.cs" />
<Compile Include="Controls\ExtendedTableView.cs" /> <Compile Include="Controls\ExtendedTableView.cs" />
<Compile Include="Controls\ExtendedPicker.cs" /> <Compile Include="Controls\ExtendedPicker.cs" />
<Compile Include="Controls\ExtendedEntry.cs" /> <Compile Include="Controls\ExtendedEntry.cs" />
<Compile Include="Controls\ExtendedTabbedPage.cs" /> <Compile Include="Controls\ExtendedTabbedPage.cs" />
<Compile Include="Controls\FormEditorCell.cs" />
<Compile Include="Controls\FormPickerCell.cs" />
<Compile Include="Controls\FormEntryCell.cs" />
<Compile Include="Models\Api\ApiError.cs" /> <Compile Include="Models\Api\ApiError.cs" />
<Compile Include="Models\Api\ApiResult.cs" /> <Compile Include="Models\Api\ApiResult.cs" />
<Compile Include="Models\Api\Request\FolderRequest.cs" /> <Compile Include="Models\Api\Request\FolderRequest.cs" />

View file

@ -0,0 +1,23 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class DismissModalToolBarItem : ToolbarItem
{
private readonly ContentPage _page;
public DismissModalToolBarItem(ContentPage page, string text = null)
{
_page = page;
Text = text ?? "Close";
Clicked += ClickedItem;
Priority = -1;
}
private async void ClickedItem(object sender, EventArgs e)
{
await _page.Navigation.PopModalAsync();
}
}
}

View file

@ -0,0 +1,27 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class ExtendedNavigationPage : NavigationPage
{
public ExtendedNavigationPage()
: base()
{
SetDefaults();
}
public ExtendedNavigationPage(Page root)
: base(root)
{
SetDefaults();
}
private void SetDefaults()
{
// default colors for our app
BarBackgroundColor = Color.FromHex("3c8dbc");
BarTextColor = Color.FromHex("ffffff");
}
}
}

View file

@ -0,0 +1,34 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class FormEditorCell : ViewCell
{
public FormEditorCell(Keyboard entryKeyboard = null, double? height = null)
{
Editor = new ExtendedEditor
{
Keyboard = entryKeyboard,
HasBorder = false
};
if(height.HasValue)
{
Editor.HeightRequest = height.Value;
}
var stackLayout = new StackLayout
{
Padding = new Thickness(15, 15, 15, 0),
BackgroundColor = Color.White
};
stackLayout.Children.Add(Editor);
View = stackLayout;
}
public ExtendedEditor Editor { get; private set; }
}
}

View file

@ -0,0 +1,38 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class FormEntryCell : ViewCell
{
public FormEntryCell(string labelText, Keyboard entryKeyboard = null, bool IsPassword = false)
{
Label = new Label
{
Text = labelText,
FontSize = 14,
TextColor = Color.FromHex("777777")
};
Entry = new ExtendedEntry
{
Keyboard = entryKeyboard,
HasBorder = false
};
var stackLayout = new StackLayout
{
Padding = new Thickness(15, 15, 15, 0),
BackgroundColor = Color.White
};
stackLayout.Children.Add(Label);
stackLayout.Children.Add(Entry);
View = stackLayout;
}
public Label Label { get; private set; }
public ExtendedEntry Entry { get; private set; }
}
}

View file

@ -0,0 +1,44 @@
using System;
using Bit.App.Resources;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class FormPickerCell : ViewCell
{
public FormPickerCell(string labelText, string[] pickerItems)
{
Label = new Label
{
Text = labelText,
FontSize = 14,
TextColor = Color.FromHex("777777")
};
Picker = new ExtendedPicker
{
HasBorder = false
};
foreach(var item in pickerItems)
{
Picker.Items.Add(item);
}
Picker.SelectedIndex = 0;
var stackLayout = new StackLayout
{
Padding = new Thickness(15, 15, 15, 0),
BackgroundColor = Color.White
};
stackLayout.Children.Add(Label);
stackLayout.Children.Add(Picker);
View = stackLayout;
}
public Label Label { get; private set; }
public ExtendedPicker Picker { get; private set; }
}
}

View file

@ -12,12 +12,9 @@ namespace Bit.App.Pages
BarTintColor = Color.FromHex("222d32"); BarTintColor = Color.FromHex("222d32");
TintColor = Color.FromHex("ffffff"); TintColor = Color.FromHex("ffffff");
var settingsNavigation = new NavigationPage(new SettingsPage()); var settingsNavigation = new ExtendedNavigationPage(new SettingsPage());
var vaultNavigation = new NavigationPage(new VaultListPage()); var vaultNavigation = new ExtendedNavigationPage(new VaultListPage());
var syncNavigation = new NavigationPage(new SyncPage()); var syncNavigation = new ExtendedNavigationPage(new SyncPage());
vaultNavigation.BarBackgroundColor = settingsNavigation.BarBackgroundColor = syncNavigation.BarBackgroundColor = Color.FromHex("3c8dbc");
vaultNavigation.BarTextColor = settingsNavigation.BarTextColor = syncNavigation.BarTextColor = Color.FromHex("ffffff");
vaultNavigation.Title = AppResources.MyVault; vaultNavigation.Title = AppResources.MyVault;
vaultNavigation.Icon = "fa-lock"; vaultNavigation.Icon = "fa-lock";

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Acr.UserDialogs; using Acr.UserDialogs;
using Bit.App.Abstractions; using Bit.App.Abstractions;
@ -30,55 +31,20 @@ namespace Bit.App.Pages
private void Init() private void Init()
{ {
var folders = _folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt()); var uriCell = new FormEntryCell(AppResources.URI, Keyboard.Url);
var nameCell = new FormEntryCell(AppResources.Name);
var usernameCell = new FormEntryCell(AppResources.Username);
var passwordCell = new FormEntryCell(AppResources.Password, IsPassword: true);
var uriEntry = new ExtendedEntry { Keyboard = Keyboard.Url, HasBorder = false }; var folderOptions = new List<string> { AppResources.FolderNone };
var nameEntry = new ExtendedEntry { HasBorder = false }; var folders = _folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt());
var folderPicker = new ExtendedPicker { Title = AppResources.Folder, HasBorder = false };
folderPicker.Items.Add(AppResources.FolderNone);
folderPicker.SelectedIndex = 0;
foreach(var folder in folders) foreach(var folder in folders)
{ {
folderPicker.Items.Add(folder.Name.Decrypt()); folderOptions.Add(folder.Name.Decrypt());
} }
var usernameEntry = new ExtendedEntry { HasBorder = false }; var folderCell = new FormPickerCell(AppResources.Folder, folderOptions.ToArray());
var passwordEntry = new ExtendedEntry { IsPassword = true, HasBorder = false };
var notesEditor = new ExtendedEditor { HeightRequest = 90, HasBorder = false };
var uriStackLayout = new FormEntryStackLayout(); var notesCell = new FormEditorCell(height:90);
uriStackLayout.Children.Add(new EntryLabel { Text = AppResources.URI });
uriStackLayout.Children.Add(uriEntry);
var uriCell = new ViewCell();
uriCell.View = uriStackLayout;
var nameStackLayout = new FormEntryStackLayout();
nameStackLayout.Children.Add(new EntryLabel { Text = AppResources.Name });
nameStackLayout.Children.Add(nameEntry);
var nameCell = new ViewCell();
nameCell.View = nameStackLayout;
var folderStackLayout = new FormEntryStackLayout();
folderStackLayout.Children.Add(new EntryLabel { Text = AppResources.Folder });
folderStackLayout.Children.Add(folderPicker);
var folderCell = new ViewCell();
folderCell.View = folderStackLayout;
var usernameStackLayout = new FormEntryStackLayout();
usernameStackLayout.Children.Add(new EntryLabel { Text = AppResources.Username });
usernameStackLayout.Children.Add(usernameEntry);
var usernameCell = new ViewCell();
usernameCell.View = usernameStackLayout;
var passwordStackLayout = new FormEntryStackLayout();
passwordStackLayout.Children.Add(new EntryLabel { Text = AppResources.Password });
passwordStackLayout.Children.Add(passwordEntry);
var passwordCell = new ViewCell();
passwordCell.View = passwordStackLayout;
var notesStackLayout = new FormEntryStackLayout();
notesStackLayout.Children.Add(notesEditor);
var notesCell = new ViewCell();
notesCell.View = notesStackLayout;
var mainTable = new ExtendedTableView var mainTable = new ExtendedTableView
{ {
@ -88,7 +54,7 @@ namespace Bit.App.Pages
EnableSelection = false, EnableSelection = false,
Root = new TableRoot Root = new TableRoot
{ {
new TableSection new TableSection("Site Information")
{ {
uriCell, uriCell,
nameCell, nameCell,
@ -123,13 +89,13 @@ namespace Bit.App.Pages
return; return;
} }
if(string.IsNullOrWhiteSpace(uriEntry.Text)) if(string.IsNullOrWhiteSpace(uriCell.Entry.Text))
{ {
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok); await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok);
return; return;
} }
if(string.IsNullOrWhiteSpace(nameEntry.Text)) if(string.IsNullOrWhiteSpace(nameCell.Entry.Text))
{ {
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok); await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok);
return; return;
@ -137,16 +103,16 @@ namespace Bit.App.Pages
var site = new Site var site = new Site
{ {
Uri = uriEntry.Text.Encrypt(), Uri = uriCell.Entry.Text.Encrypt(),
Name = nameEntry.Text.Encrypt(), Name = nameCell.Entry.Text.Encrypt(),
Username = usernameEntry.Text?.Encrypt(), Username = usernameCell.Entry.Text?.Encrypt(),
Password = passwordEntry.Text?.Encrypt(), Password = passwordCell.Entry.Text?.Encrypt(),
Notes = notesEditor.Text?.Encrypt(), Notes = notesCell.Editor.Text?.Encrypt(),
}; };
if(folderPicker.SelectedIndex > 0) if(folderCell.Picker.SelectedIndex > 0)
{ {
site.FolderId = folders.ElementAt(folderPicker.SelectedIndex - 1).Id; site.FolderId = folders.ElementAt(folderCell.Picker.SelectedIndex - 1).Id;
} }
var saveTask = _siteService.SaveAsync(site); var saveTask = _siteService.SaveAsync(site);
@ -155,12 +121,13 @@ namespace Bit.App.Pages
_userDialogs.HideLoading(); _userDialogs.HideLoading();
await Navigation.PopAsync(); await Navigation.PopAsync();
_userDialogs.SuccessToast(nameEntry.Text, "New site created."); _userDialogs.SuccessToast(nameCell.Entry.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);
ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel"));
if(!_connectivity.IsConnected) if(!_connectivity.IsConnected)
{ {

View file

@ -1,10 +1,9 @@
using System; using System;
using System.Collections.Generic; 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.Controls;
using Bit.App.Resources; using Bit.App.Resources;
using Plugin.Connectivity.Abstractions; using Plugin.Connectivity.Abstractions;
using Xamarin.Forms; using Xamarin.Forms;
@ -40,12 +39,17 @@ namespace Bit.App.Pages
return; return;
} }
var folders = _folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt()); var uriCell = new FormEntryCell(AppResources.URI, Keyboard.Url);
uriCell.Entry.Text = site.Uri?.Decrypt();
var nameCell = new FormEntryCell(AppResources.Name);
nameCell.Entry.Text = site.Name?.Decrypt();
var usernameCell = new FormEntryCell(AppResources.Username);
usernameCell.Entry.Text = site.Username?.Decrypt();
var passwordCell = new FormEntryCell(AppResources.Password, IsPassword: true);
passwordCell.Entry.Text = site.Password?.Decrypt();
var uriEntry = new Entry { Keyboard = Keyboard.Url, Text = site.Uri?.Decrypt() }; var folderOptions = new List<string> { AppResources.FolderNone };
var nameEntry = new Entry { Text = site.Name?.Decrypt() }; var folders = _folderService.GetAllAsync().GetAwaiter().GetResult().OrderBy(f => f.Name?.Decrypt());
var folderPicker = new Picker { Title = AppResources.Folder };
folderPicker.Items.Add(AppResources.FolderNone);
int selectedIndex = 0; int selectedIndex = 0;
int i = 0; int i = 0;
foreach(var folder in folders) foreach(var folder in folders)
@ -56,30 +60,46 @@ namespace Bit.App.Pages
selectedIndex = i; selectedIndex = i;
} }
folderPicker.Items.Add(folder.Name.Decrypt()); folderOptions.Add(folder.Name.Decrypt());
} }
folderPicker.SelectedIndex = selectedIndex; var folderCell = new FormPickerCell(AppResources.Folder, folderOptions.ToArray());
var usernameEntry = new Entry { Text = site.Username?.Decrypt() }; folderCell.Picker.SelectedIndex = selectedIndex;
var passwordEntry = new Entry { IsPassword = true, Text = site.Password?.Decrypt() };
var notesEditor = new Editor { Text = site.Notes?.Decrypt() };
var stackLayout = new StackLayout(); var notesCell = new FormEditorCell(height: 90);
stackLayout.Children.Add(new Label { Text = AppResources.URI }); notesCell.Editor.Text = site.Notes?.Decrypt();
stackLayout.Children.Add(uriEntry);
stackLayout.Children.Add(new Label { Text = AppResources.Name }); var table = new ExtendedTableView
stackLayout.Children.Add(nameEntry); {
stackLayout.Children.Add(new Label { Text = AppResources.Folder }); Intent = TableIntent.Settings,
stackLayout.Children.Add(folderPicker); EnableScrolling = false,
stackLayout.Children.Add(new Label { Text = AppResources.Username }); HasUnevenRows = true,
stackLayout.Children.Add(usernameEntry); EnableSelection = false,
stackLayout.Children.Add(new Label { Text = AppResources.Password }); Root = new TableRoot
stackLayout.Children.Add(passwordEntry); {
stackLayout.Children.Add(new Label { Text = AppResources.Notes }); new TableSection("Site Information")
stackLayout.Children.Add(notesEditor); {
uriCell,
nameCell,
folderCell,
usernameCell,
passwordCell
},
new TableSection(AppResources.Notes)
{
notesCell
}
}
};
if(Device.OS == TargetPlatform.iOS)
{
table.RowHeight = -1;
table.EstimatedRowHeight = 70;
}
var scrollView = new ScrollView var scrollView = new ScrollView
{ {
Content = stackLayout, Content = table,
Orientation = ScrollOrientation.Vertical Orientation = ScrollOrientation.Vertical
}; };
@ -91,27 +111,31 @@ namespace Bit.App.Pages
return; return;
} }
if(string.IsNullOrWhiteSpace(uriEntry.Text)) if(string.IsNullOrWhiteSpace(uriCell.Entry.Text))
{ {
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok); await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.URI), AppResources.Ok);
return; return;
} }
if(string.IsNullOrWhiteSpace(nameEntry.Text)) if(string.IsNullOrWhiteSpace(nameCell.Entry.Text))
{ {
await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok); await DisplayAlert(AppResources.AnErrorHasOccurred, string.Format(AppResources.ValidationFieldRequired, AppResources.Name), AppResources.Ok);
return; return;
} }
site.Uri = uriEntry.Text.Encrypt(); site.Uri = uriCell.Entry.Text.Encrypt();
site.Name = nameEntry.Text.Encrypt(); site.Name = nameCell.Entry.Text.Encrypt();
site.Username = usernameEntry.Text?.Encrypt(); site.Username = usernameCell.Entry.Text?.Encrypt();
site.Password = passwordEntry.Text?.Encrypt(); site.Password = passwordCell.Entry.Text?.Encrypt();
site.Notes = notesEditor.Text?.Encrypt(); site.Notes = notesCell.Editor.Text?.Encrypt();
if(folderPicker.SelectedIndex > 0) if(folderCell.Picker.SelectedIndex > 0)
{ {
site.FolderId = folders.ElementAt(folderPicker.SelectedIndex - 1).Id; site.FolderId = folders.ElementAt(folderCell.Picker.SelectedIndex - 1).Id;
}
else
{
site.FolderId = null;
} }
var saveTask = _siteService.SaveAsync(site); var saveTask = _siteService.SaveAsync(site);
@ -119,13 +143,14 @@ namespace Bit.App.Pages
await saveTask; await saveTask;
_userDialogs.HideLoading(); _userDialogs.HideLoading();
await Navigation.PopAsync(); await Navigation.PopModalAsync();
_userDialogs.SuccessToast(nameEntry.Text, "Site updated."); _userDialogs.SuccessToast(nameCell.Entry.Text, "Site updated.");
}, ToolbarItemOrder.Default, 0); }, ToolbarItemOrder.Default, 0);
Title = "Edit Site"; Title = "Edit Site";
Content = scrollView; Content = scrollView;
ToolbarItems.Add(saveToolBarItem); ToolbarItems.Add(saveToolBarItem);
ToolbarItems.Add(new DismissModalToolBarItem(this, "Cancel"));
if(!_connectivity.IsConnected) if(!_connectivity.IsConnected)
{ {

View file

@ -4,6 +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.Controls;
using Bit.App.Models.Page; using Bit.App.Models.Page;
using Bit.App.Resources; using Bit.App.Resources;
using Xamarin.Forms; using Xamarin.Forms;
@ -71,7 +72,8 @@ namespace Bit.App.Pages
private void SiteSelected(object sender, SelectedItemChangedEventArgs e) private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
{ {
var site = e.SelectedItem as VaultListPageModel.Site; var site = e.SelectedItem as VaultListPageModel.Site;
Navigation.PushAsync(new VaultViewSitePage(site.Id)); var page = new ExtendedNavigationPage(new VaultViewSitePage(site.Id));
Navigation.PushModalAsync(page);
} }
private async void MoreClickedAsync(object sender, EventArgs e) private async void MoreClickedAsync(object sender, EventArgs e)
@ -83,11 +85,13 @@ namespace Bit.App.Pages
if(selection == AppResources.View) if(selection == AppResources.View)
{ {
await Navigation.PushAsync(new VaultViewSitePage(site.Id)); var page = new ExtendedNavigationPage(new VaultViewSitePage(site.Id));
await Navigation.PushModalAsync(page);
} }
else if(selection == AppResources.Edit) else if(selection == AppResources.Edit)
{ {
// TODO: navigate to edit page var page = new ExtendedNavigationPage(new VaultEditSitePage(site.Id));
await Navigation.PushModalAsync(page);
} }
else if(selection == AppResources.CopyPassword) else if(selection == AppResources.CopyPassword)
{ {
@ -147,7 +151,8 @@ namespace Bit.App.Pages
private async void ClickedItem(object sender, EventArgs e) private async void ClickedItem(object sender, EventArgs e)
{ {
await _page.Navigation.PushAsync(new VaultAddSitePage()); var page = new ExtendedNavigationPage(new VaultAddSitePage());
await _page.Navigation.PushModalAsync(page);
} }
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using Acr.UserDialogs; using Acr.UserDialogs;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Models.Page; using Bit.App.Models.Page;
using Bit.App.Resources; using Bit.App.Resources;
using Xamarin.Forms; using Xamarin.Forms;
@ -30,6 +31,7 @@ namespace Bit.App.Pages
private void Init() private void Init()
{ {
ToolbarItems.Add(new EditSiteToolBarItem(this, _siteId)); ToolbarItems.Add(new EditSiteToolBarItem(this, _siteId));
ToolbarItems.Add(new DismissModalToolBarItem(this));
var stackLayout = new StackLayout(); var stackLayout = new StackLayout();
// Username // Username
@ -157,7 +159,8 @@ namespace Bit.App.Pages
private async void ClickedItem(object sender, EventArgs e) private async void ClickedItem(object sender, EventArgs e)
{ {
await _page.Navigation.PushAsync(new VaultEditSitePage(_siteId)); var page = new ExtendedNavigationPage(new VaultEditSitePage(_siteId));
await _page.Navigation.PushModalAsync(page);
} }
} }
} }

View file

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Bit.iOS.Controls;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(ContentPage), typeof(ContentPageRenderer))]
namespace Bit.iOS.Controls
{
public class ContentPageRenderer : PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var contentPage = Element as ContentPage;
if(contentPage == null || NavigationController == null)
{
return;
}
var itemsInfo = contentPage.ToolbarItems;
var navigationItem = NavigationController.TopViewController.NavigationItem;
var leftNativeButtons = (navigationItem.LeftBarButtonItems ?? new UIBarButtonItem[] { }).ToList();
var rightNativeButtons = (navigationItem.RightBarButtonItems ?? new UIBarButtonItem[] { }).ToList();
var newLeftButtons = new List<UIBarButtonItem>();
var newRightButtons = new List<UIBarButtonItem>();
rightNativeButtons.ForEach(nativeItem =>
{
// Use reflection to get Xamarin private field "_item"
var field = nativeItem.GetType().GetField("_item", BindingFlags.NonPublic | BindingFlags.Instance);
if(field == null)
{
return;
}
var info = field.GetValue(nativeItem) as ToolbarItem;
if(info == null)
{
return;
}
if(info.Priority < 0)
{
newLeftButtons.Add(nativeItem);
}
else
{
newRightButtons.Add(nativeItem);
}
});
leftNativeButtons.ForEach(nativeItem =>
{
newLeftButtons.Add(nativeItem);
});
navigationItem.RightBarButtonItems = newRightButtons.ToArray();
navigationItem.LeftBarButtonItems = newLeftButtons.ToArray();
}
}
}

View file

@ -101,6 +101,7 @@
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Controls\ContentPageRenderer.cs" />
<Compile Include="Controls\ExtendedTableViewRenderer.cs" /> <Compile Include="Controls\ExtendedTableViewRenderer.cs" />
<Compile Include="Controls\ExtendedPickerRenderer.cs" /> <Compile Include="Controls\ExtendedPickerRenderer.cs" />
<Compile Include="Controls\ExtendedEntryRenderer.cs" /> <Compile Include="Controls\ExtendedEntryRenderer.cs" />