1
0
mirror of https://github.com/bitwarden/mobile.git synced 2024-11-30 12:54:24 +01:00

redraw stack layouts on ios tableviews

This commit is contained in:
Kyle Spearrin 2018-01-03 12:18:15 -05:00
parent fa9e22730a
commit 9456f5dc31
16 changed files with 130 additions and 103 deletions

View File

@ -1,6 +1,4 @@
using Xamarin.Forms; using Xamarin.Forms;
using XLabs.Ioc;
using Bit.App.Abstractions;
using System; using System;
using System.Reflection; using System.Reflection;
@ -42,6 +40,7 @@ namespace Bit.App.Controls
public bool NoHeader { get; set; } public bool NoHeader { get; set; }
public bool NoFooter { get; set; } public bool NoFooter { get; set; }
public int BottomPadding { get; set; } public int BottomPadding { get; set; }
public Func<RedrawableStackLayout> WrappingStackLayout { get; set; }
protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint) protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint)
{ {

View File

@ -0,0 +1,27 @@
using System;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Controls
{
public class RedrawableStackLayout : StackLayout
{
private DateTime _lastRedraw = DateTime.MinValue;
private TimeSpan _redrawThreshold = TimeSpan.FromMilliseconds(1000);
public async Task RedrawIfNeededAsync(int delay = 0, bool force = false)
{
var now = DateTime.UtcNow;
if(Device.RuntimePlatform == Device.iOS && (force || (now - _lastRedraw) > _redrawThreshold))
{
_lastRedraw = now;
if(delay > 0)
{
await Task.Delay(delay);
}
InvalidateLayout();
}
}
}
}

View File

@ -30,7 +30,7 @@ namespace Bit.App.Pages
public FormEntryCell ApiUrlCell { get; set; } public FormEntryCell ApiUrlCell { get; set; }
public FormEntryCell IdentityUrlCell { get; set; } public FormEntryCell IdentityUrlCell { get; set; }
public FormEntryCell IconsUrlCell { get; set; } public FormEntryCell IconsUrlCell { get; set; }
public StackLayout StackLayout { get; set; } public RedrawableStackLayout StackLayout { get; set; }
public Label SelfHostLabel { get; set; } public Label SelfHostLabel { get; set; }
public Label CustomLabel { get; set; } public Label CustomLabel { get; set; }
@ -57,7 +57,7 @@ namespace Bit.App.Pages
entryKeyboard: Keyboard.Url); entryKeyboard: Keyboard.Url);
BaseUrlCell.Entry.Text = _appSettings.BaseUrl; BaseUrlCell.Entry.Text = _appSettings.BaseUrl;
var table = new FormTableView var table = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -74,10 +74,10 @@ namespace Bit.App.Pages
LineBreakMode = LineBreakMode.WordWrap, LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)), FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"], Style = (Style)Application.Current.Resources["text-muted"],
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25) Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 5)
}; };
var table2 = new FormTableView var table2 = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -97,10 +97,10 @@ namespace Bit.App.Pages
LineBreakMode = LineBreakMode.WordWrap, LineBreakMode = LineBreakMode.WordWrap,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)), FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"], Style = (Style)Application.Current.Resources["text-muted"],
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25) Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 5)
}; };
StackLayout = new StackLayout StackLayout = new RedrawableStackLayout
{ {
Children = { table, SelfHostLabel, table2, CustomLabel }, Children = { table, SelfHostLabel, table2, CustomLabel },
Spacing = 0 Spacing = 0
@ -138,7 +138,6 @@ namespace Bit.App.Pages
IdentityUrlCell.InitEvents(); IdentityUrlCell.InitEvents();
ApiUrlCell.InitEvents(); ApiUrlCell.InitEvents();
WebVaultUrlCell.InitEvents(); WebVaultUrlCell.InitEvents();
StackLayout.LayoutChanged += Layout_LayoutChanged;
BaseUrlCell.Entry.FocusWithDelay(); BaseUrlCell.Entry.FocusWithDelay();
} }
protected override void OnDisappearing() protected override void OnDisappearing()
@ -149,13 +148,6 @@ namespace Bit.App.Pages
IdentityUrlCell.Dispose(); IdentityUrlCell.Dispose();
ApiUrlCell.Dispose(); ApiUrlCell.Dispose();
WebVaultUrlCell.Dispose(); WebVaultUrlCell.Dispose();
StackLayout.LayoutChanged -= Layout_LayoutChanged;
}
private void Layout_LayoutChanged(object sender, EventArgs e)
{
SelfHostLabel.WidthRequest = StackLayout.Bounds.Width - SelfHostLabel.Bounds.Left * 2;
CustomLabel.WidthRequest = StackLayout.Bounds.Width - CustomLabel.Bounds.Left * 2;
} }
private async Task SaveAsync() private async Task SaveAsync()
@ -259,7 +251,7 @@ namespace Bit.App.Pages
private class FormTableView : ExtendedTableView private class FormTableView : ExtendedTableView
{ {
public FormTableView() public FormTableView(EnvironmentPage page)
{ {
Intent = TableIntent.Settings; Intent = TableIntent.Settings;
EnableScrolling = false; EnableScrolling = false;
@ -267,6 +259,7 @@ namespace Bit.App.Pages
EnableSelection = true; EnableSelection = true;
VerticalOptions = LayoutOptions.Start; VerticalOptions = LayoutOptions.Start;
NoFooter = true; NoFooter = true;
WrappingStackLayout = () => page.StackLayout;
} }
} }
} }

View File

@ -67,12 +67,14 @@ namespace Bit.App.Pages
Uppercase = false Uppercase = false
}; };
var stackLayout = new StackLayout var stackLayout = new RedrawableStackLayout
{ {
Spacing = 10, Spacing = 10,
Children = { table, logoutButton } Children = { table, logoutButton }
}; };
table.WrappingStackLayout = () => stackLayout;
var scrollView = new ScrollView { Content = stackLayout }; var scrollView = new ScrollView { Content = stackLayout };
if(Device.RuntimePlatform == Device.iOS) if(Device.RuntimePlatform == Device.iOS)

View File

@ -71,7 +71,6 @@ namespace Bit.App.Pages
HasUnevenRows = true, HasUnevenRows = true,
EnableSelection = true, EnableSelection = true,
NoFooter = true, NoFooter = true,
//NoHeader = true,
VerticalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start,
Root = new TableRoot Root = new TableRoot
{ {
@ -87,18 +86,20 @@ namespace Bit.App.Pages
{ {
Text = AppResources.GetPasswordHint, Text = AppResources.GetPasswordHint,
Style = (Style)Application.Current.Resources["btn-primaryAccent"], Style = (Style)Application.Current.Resources["btn-primaryAccent"],
Margin = new Thickness(15, 0, 15, 25),
Command = new Command(async () => await ForgotPasswordAsync()), Command = new Command(async () => await ForgotPasswordAsync()),
VerticalOptions = LayoutOptions.End,
Uppercase = false, Uppercase = false,
BackgroundColor = Color.Transparent BackgroundColor = Color.Transparent
}; };
var layout = new StackLayout var layout = new RedrawableStackLayout
{ {
Children = { table, forgotPasswordButton }, Children = { table, forgotPasswordButton },
Spacing = Helpers.OnPlatform(iOS: 0, Android: 10, Windows: 0) Spacing = 10
}; };
table.WrappingStackLayout = () => layout;
var scrollView = new ScrollView { Content = layout }; var scrollView = new ScrollView { Content = layout };
if(Device.RuntimePlatform == Device.iOS) if(Device.RuntimePlatform == Device.iOS)

View File

@ -135,12 +135,13 @@ namespace Bit.App.Pages
RememberCell RememberCell
}); });
var layout = new StackLayout var layout = new RedrawableStackLayout
{ {
Children = { instruction, table }, Children = { instruction, table },
Spacing = 0 Spacing = 0
}; };
table.WrappingStackLayout = () => layout;
scrollView.Content = layout; scrollView.Content = layout;
switch(_providerType.Value) switch(_providerType.Value)
@ -213,12 +214,13 @@ namespace Bit.App.Pages
RememberCell RememberCell
}); });
var layout = new StackLayout var layout = new RedrawableStackLayout
{ {
Children = { webView, table, anotherMethodButton }, Children = { webView, table, anotherMethodButton },
Spacing = 0 Spacing = 0
}; };
table.WrappingStackLayout = () => layout;
scrollView.Content = layout; scrollView.Content = layout;
Title = "Duo"; Title = "Duo";
@ -244,12 +246,13 @@ namespace Bit.App.Pages
RememberCell RememberCell
}); });
var layout = new StackLayout var layout = new RedrawableStackLayout
{ {
Children = { instruction, image, table, anotherMethodButton }, Children = { instruction, image, table, anotherMethodButton },
Spacing = 0 Spacing = 0
}; };
table.WrappingStackLayout = () => layout;
scrollView.Content = layout; scrollView.Content = layout;
Title = AppResources.YubiKeyTitle; Title = AppResources.YubiKeyTitle;
@ -524,7 +527,7 @@ namespace Bit.App.Pages
NoFooter = true; NoFooter = true;
NoHeader = true; NoHeader = true;
VerticalOptions = LayoutOptions.Start; VerticalOptions = LayoutOptions.Start;
Root = Root = new TableRoot Root = new TableRoot
{ {
section section
}; };

View File

@ -64,12 +64,13 @@ namespace Bit.App.Pages
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25) Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
}; };
var layout = new StackLayout var layout = new RedrawableStackLayout
{ {
Children = { table, hintLabel }, Children = { table, hintLabel },
Spacing = 0 Spacing = 0
}; };
table.WrappingStackLayout = () => layout;
var scrollView = new ScrollView { Content = layout }; var scrollView = new ScrollView { Content = layout };
if(Device.RuntimePlatform == Device.iOS) if(Device.RuntimePlatform == Device.iOS)

View File

@ -35,7 +35,7 @@ namespace Bit.App.Pages
public FormEntryCell PasswordCell { get; set; } public FormEntryCell PasswordCell { get; set; }
public FormEntryCell ConfirmPasswordCell { get; set; } public FormEntryCell ConfirmPasswordCell { get; set; }
public FormEntryCell PasswordHintCell { get; set; } public FormEntryCell PasswordHintCell { get; set; }
public StackLayout StackLayout { get; set; } public RedrawableStackLayout StackLayout { get; set; }
public Label PasswordLabel { get; set; } public Label PasswordLabel { get; set; }
public Label HintLabel { get; set; } public Label HintLabel { get; set; }
@ -62,7 +62,7 @@ namespace Bit.App.Pages
PasswordHintCell.Entry.ReturnType = Enums.ReturnType.Done; PasswordHintCell.Entry.ReturnType = Enums.ReturnType.Done;
var table = new FormTableView var table = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -83,7 +83,7 @@ namespace Bit.App.Pages
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25) Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
}; };
var table2 = new FormTableView var table2 = new FormTableView(this)
{ {
NoHeader = true, NoHeader = true,
Root = new TableRoot Root = new TableRoot
@ -105,7 +105,7 @@ namespace Bit.App.Pages
Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25) Margin = new Thickness(15, (this.IsLandscape() ? 5 : 0), 15, 25)
}; };
StackLayout = new StackLayout StackLayout = new RedrawableStackLayout
{ {
Children = { table, PasswordLabel, table2, HintLabel }, Children = { table, PasswordLabel, table2, HintLabel },
Spacing = 0 Spacing = 0
@ -145,7 +145,6 @@ namespace Bit.App.Pages
PasswordHintCell.InitEvents(); PasswordHintCell.InitEvents();
ConfirmPasswordCell.InitEvents(); ConfirmPasswordCell.InitEvents();
PasswordHintCell.Entry.Completed += Entry_Completed; PasswordHintCell.Entry.Completed += Entry_Completed;
StackLayout.LayoutChanged += Layout_LayoutChanged;
EmailCell.Entry.FocusWithDelay(); EmailCell.Entry.FocusWithDelay();
} }
protected override void OnDisappearing() protected override void OnDisappearing()
@ -156,13 +155,6 @@ namespace Bit.App.Pages
PasswordHintCell.Dispose(); PasswordHintCell.Dispose();
ConfirmPasswordCell.Dispose(); ConfirmPasswordCell.Dispose();
PasswordHintCell.Entry.Completed -= Entry_Completed; PasswordHintCell.Entry.Completed -= Entry_Completed;
StackLayout.LayoutChanged -= Layout_LayoutChanged;
}
private void Layout_LayoutChanged(object sender, EventArgs e)
{
PasswordLabel.WidthRequest = StackLayout.Bounds.Width - PasswordLabel.Bounds.Left * 2;
HintLabel.WidthRequest = StackLayout.Bounds.Width - HintLabel.Bounds.Left * 2;
} }
private async void Entry_Completed(object sender, EventArgs e) private async void Entry_Completed(object sender, EventArgs e)
@ -229,7 +221,7 @@ namespace Bit.App.Pages
private class FormTableView : ExtendedTableView private class FormTableView : ExtendedTableView
{ {
public FormTableView() public FormTableView(RegisterPage page)
{ {
Intent = TableIntent.Settings; Intent = TableIntent.Settings;
EnableScrolling = false; EnableScrolling = false;
@ -237,6 +229,7 @@ namespace Bit.App.Pages
EnableSelection = true; EnableSelection = true;
VerticalOptions = LayoutOptions.Start; VerticalOptions = LayoutOptions.Start;
NoFooter = true; NoFooter = true;
WrappingStackLayout = () => page.StackLayout;
} }
} }
} }

View File

@ -73,12 +73,14 @@ namespace Bit.App.Pages
table.EstimatedRowHeight = 44; table.EstimatedRowHeight = 44;
} }
var stackLayout = new StackLayout var stackLayout = new RedrawableStackLayout
{ {
Children = { logoVersionStackLayout, table }, Children = { logoVersionStackLayout, table },
Spacing = 0 Spacing = 0
}; };
table.WrappingStackLayout = () => stackLayout;
if(Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.UWP) if(Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.UWP)
{ {
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close)); ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close));

View File

@ -50,9 +50,7 @@ namespace Bit.App.Pages
var mainTable = new ExtendedTableView var mainTable = new ExtendedTableView
{ {
Intent = TableIntent.Settings, Intent = TableIntent.Settings,
EnableScrolling = false,
HasUnevenRows = true, HasUnevenRows = true,
VerticalOptions = LayoutOptions.Start,
Root = new TableRoot Root = new TableRoot
{ {
new TableSection(Helpers.GetEmptyTableSectionTitle()) new TableSection(Helpers.GetEmptyTableSectionTitle())

View File

@ -22,7 +22,7 @@ namespace Bit.App.Pages
public ExtendedTextCell EmailCell { get; set; } public ExtendedTextCell EmailCell { get; set; }
public ExtendedTextCell WebsiteCell { get; set; } public ExtendedTextCell WebsiteCell { get; set; }
public ExtendedTextCell BugCell { get; set; } public ExtendedTextCell BugCell { get; set; }
public StackLayout StackLayout { get; set; } public RedrawableStackLayout StackLayout { get; set; }
private CustomLabel EmailLabel { get; set; } private CustomLabel EmailLabel { get; set; }
private CustomLabel WebsiteLabel { get; set; } private CustomLabel WebsiteLabel { get; set; }
private CustomLabel BugLabel { get; set; } private CustomLabel BugLabel { get; set; }
@ -35,7 +35,7 @@ namespace Bit.App.Pages
ShowDisclousure = true ShowDisclousure = true
}; };
var emailTable = new CustomTableView var emailTable = new CustomTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -57,7 +57,7 @@ namespace Bit.App.Pages
ShowDisclousure = true ShowDisclousure = true
}; };
var websiteTable = new CustomTableView var websiteTable = new CustomTableView(this)
{ {
NoHeader = true, NoHeader = true,
Root = new TableRoot Root = new TableRoot
@ -80,7 +80,7 @@ namespace Bit.App.Pages
ShowDisclousure = true ShowDisclousure = true
}; };
var bugTable = new CustomTableView var bugTable = new CustomTableView(this)
{ {
NoHeader = true, NoHeader = true,
Root = new TableRoot Root = new TableRoot
@ -97,7 +97,7 @@ namespace Bit.App.Pages
Text = AppResources.FileBugReportDescription Text = AppResources.FileBugReportDescription
}; };
StackLayout = new StackLayout StackLayout = new RedrawableStackLayout
{ {
Children = { emailTable, EmailLabel, websiteTable, WebsiteLabel, bugTable, BugLabel }, Children = { emailTable, EmailLabel, websiteTable, WebsiteLabel, bugTable, BugLabel },
Spacing = 0 Spacing = 0
@ -118,7 +118,6 @@ namespace Bit.App.Pages
EmailCell.Tapped += EmailCell_Tapped; EmailCell.Tapped += EmailCell_Tapped;
WebsiteCell.Tapped += WebsiteCell_Tapped; WebsiteCell.Tapped += WebsiteCell_Tapped;
BugCell.Tapped += BugCell_Tapped; BugCell.Tapped += BugCell_Tapped;
StackLayout.LayoutChanged += StackLayout_LayoutChanged;
} }
protected override void OnDisappearing() protected override void OnDisappearing()
@ -127,14 +126,6 @@ namespace Bit.App.Pages
EmailCell.Tapped -= EmailCell_Tapped; EmailCell.Tapped -= EmailCell_Tapped;
WebsiteCell.Tapped -= WebsiteCell_Tapped; WebsiteCell.Tapped -= WebsiteCell_Tapped;
BugCell.Tapped -= BugCell_Tapped; BugCell.Tapped -= BugCell_Tapped;
StackLayout.LayoutChanged -= StackLayout_LayoutChanged;
}
private void StackLayout_LayoutChanged(object sender, EventArgs e)
{
WebsiteLabel.WidthRequest = StackLayout.Bounds.Width - WebsiteLabel.Bounds.Left * 2;
EmailLabel.WidthRequest = StackLayout.Bounds.Width - EmailLabel.Bounds.Left * 2;
BugLabel.WidthRequest = StackLayout.Bounds.Width - BugLabel.Bounds.Left * 2;
} }
private void EmailCell_Tapped(object sender, EventArgs e) private void EmailCell_Tapped(object sender, EventArgs e)
@ -157,7 +148,7 @@ namespace Bit.App.Pages
private class CustomTableView : ExtendedTableView private class CustomTableView : ExtendedTableView
{ {
public CustomTableView() public CustomTableView(SettingsHelpPage page)
{ {
Intent = TableIntent.Settings; Intent = TableIntent.Settings;
EnableScrolling = false; EnableScrolling = false;
@ -165,6 +156,7 @@ namespace Bit.App.Pages
EnableSelection = true; EnableSelection = true;
VerticalOptions = LayoutOptions.Start; VerticalOptions = LayoutOptions.Start;
NoFooter = true; NoFooter = true;
WrappingStackLayout = () => page.StackLayout;
if(Device.RuntimePlatform == Device.iOS) if(Device.RuntimePlatform == Device.iOS)
{ {

View File

@ -24,7 +24,7 @@ namespace Bit.App.Pages
Init(); Init();
} }
private StackLayout StackLayout { get; set; } private RedrawableStackLayout StackLayout { get; set; }
private ExtendedSwitchCell CopyTotpCell { get; set; } private ExtendedSwitchCell CopyTotpCell { get; set; }
private Label CopyTotpLabel { get; set; } private Label CopyTotpLabel { get; set; }
private ExtendedSwitchCell AnalyticsCell { get; set; } private ExtendedSwitchCell AnalyticsCell { get; set; }
@ -46,7 +46,7 @@ namespace Bit.App.Pages
On = _appSettings.DisableWebsiteIcons On = _appSettings.DisableWebsiteIcons
}; };
var websiteIconsTable = new FormTableView(true) var websiteIconsTable = new FormTableView(this, true)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -63,7 +63,7 @@ namespace Bit.App.Pages
On = _settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false) On = _settings.GetValueOrDefault(Constants.SettingDisableTotpCopy, false)
}; };
var totpTable = new FormTableView var totpTable = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -80,7 +80,7 @@ namespace Bit.App.Pages
On = _settings.GetValueOrDefault(Constants.SettingGaOptOut, false) On = _settings.GetValueOrDefault(Constants.SettingGaOptOut, false)
}; };
var analyticsTable = new FormTableView var analyticsTable = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -106,7 +106,7 @@ namespace Bit.App.Pages
Text = AppResources.DisableWebsiteIconsDescription Text = AppResources.DisableWebsiteIconsDescription
}; };
StackLayout = new StackLayout StackLayout = new RedrawableStackLayout
{ {
Children = Children =
{ {
@ -125,7 +125,7 @@ namespace Bit.App.Pages
On = !_appSettings.AutofillPersistNotification && !_appSettings.AutofillPasswordField On = !_appSettings.AutofillPersistNotification && !_appSettings.AutofillPasswordField
}; };
var autofillAlwaysTable = new FormTableView(true) var autofillAlwaysTable = new FormTableView(this, true)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -147,7 +147,7 @@ namespace Bit.App.Pages
On = _appSettings.AutofillPersistNotification On = _appSettings.AutofillPersistNotification
}; };
var autofillPersistNotificationTable = new FormTableView var autofillPersistNotificationTable = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -169,7 +169,7 @@ namespace Bit.App.Pages
On = _appSettings.AutofillPasswordField On = _appSettings.AutofillPasswordField
}; };
var autofillPasswordFieldTable = new FormTableView var autofillPasswordFieldTable = new FormTableView(this)
{ {
Root = new TableRoot Root = new TableRoot
{ {
@ -217,7 +217,6 @@ namespace Bit.App.Pages
AnalyticsCell.OnChanged += AnalyticsCell_Changed; AnalyticsCell.OnChanged += AnalyticsCell_Changed;
WebsiteIconsCell.OnChanged += WebsiteIconsCell_Changed; WebsiteIconsCell.OnChanged += WebsiteIconsCell_Changed;
CopyTotpCell.OnChanged += CopyTotpCell_OnChanged; CopyTotpCell.OnChanged += CopyTotpCell_OnChanged;
StackLayout.LayoutChanged += Layout_LayoutChanged;
if(Device.RuntimePlatform == Device.Android) if(Device.RuntimePlatform == Device.Android)
{ {
@ -234,7 +233,6 @@ namespace Bit.App.Pages
AnalyticsCell.OnChanged -= AnalyticsCell_Changed; AnalyticsCell.OnChanged -= AnalyticsCell_Changed;
WebsiteIconsCell.OnChanged -= WebsiteIconsCell_Changed; WebsiteIconsCell.OnChanged -= WebsiteIconsCell_Changed;
CopyTotpCell.OnChanged -= CopyTotpCell_OnChanged; CopyTotpCell.OnChanged -= CopyTotpCell_OnChanged;
StackLayout.LayoutChanged -= Layout_LayoutChanged;
if(Device.RuntimePlatform == Device.Android) if(Device.RuntimePlatform == Device.Android)
{ {
@ -244,29 +242,6 @@ namespace Bit.App.Pages
} }
} }
private void Layout_LayoutChanged(object sender, EventArgs e)
{
AnalyticsLabel.WidthRequest = StackLayout.Bounds.Width - AnalyticsLabel.Bounds.Left * 2;
WebsiteIconsLabel.WidthRequest = StackLayout.Bounds.Width - WebsiteIconsLabel.Bounds.Left * 2;
CopyTotpLabel.WidthRequest = StackLayout.Bounds.Width - CopyTotpLabel.Bounds.Left * 2;
if(AutofillAlwaysLabel != null)
{
AutofillAlwaysLabel.WidthRequest = StackLayout.Bounds.Width - AutofillAlwaysLabel.Bounds.Left * 2;
}
if(AutofillPasswordFieldLabel != null)
{
AutofillPasswordFieldLabel.WidthRequest = StackLayout.Bounds.Width - AutofillPasswordFieldLabel.Bounds.Left * 2;
}
if(AutofillPersistNotificationLabel != null)
{
AutofillPersistNotificationLabel.WidthRequest =
StackLayout.Bounds.Width - AutofillPersistNotificationLabel.Bounds.Left * 2;
}
}
private void WebsiteIconsCell_Changed(object sender, ToggledEventArgs e) private void WebsiteIconsCell_Changed(object sender, ToggledEventArgs e)
{ {
var cell = sender as ExtendedSwitchCell; var cell = sender as ExtendedSwitchCell;
@ -352,7 +327,7 @@ namespace Bit.App.Pages
private class FormTableView : ExtendedTableView private class FormTableView : ExtendedTableView
{ {
public FormTableView(bool header = false) public FormTableView(SettingsOptionsPage page, bool header = false)
{ {
Intent = TableIntent.Settings; Intent = TableIntent.Settings;
EnableScrolling = false; EnableScrolling = false;
@ -361,6 +336,7 @@ namespace Bit.App.Pages
VerticalOptions = LayoutOptions.Start; VerticalOptions = LayoutOptions.Start;
NoFooter = true; NoFooter = true;
NoHeader = !header; NoHeader = !header;
WrappingStackLayout = () => page.StackLayout;
} }
} }

View File

@ -163,7 +163,7 @@ namespace Bit.App.Pages
table.BottomPadding = 50; table.BottomPadding = 50;
} }
var stackLayout = new StackLayout var stackLayout = new RedrawableStackLayout
{ {
Orientation = StackOrientation.Vertical, Orientation = StackOrientation.Vertical,
Children = { Password, table }, Children = { Password, table },
@ -171,6 +171,8 @@ namespace Bit.App.Pages
Spacing = 0 Spacing = 0
}; };
table.WrappingStackLayout = () => stackLayout;
var scrollView = new ScrollView var scrollView = new ScrollView
{ {
Content = stackLayout, Content = stackLayout,

View File

@ -44,7 +44,7 @@ namespace Bit.App.Pages
public ExtendedObservableCollection<VaultAttachmentsPageModel.Attachment> PresentationAttchments { get; private set; } public ExtendedObservableCollection<VaultAttachmentsPageModel.Attachment> PresentationAttchments { get; private set; }
= new ExtendedObservableCollection<VaultAttachmentsPageModel.Attachment>(); = new ExtendedObservableCollection<VaultAttachmentsPageModel.Attachment>();
public ExtendedListView ListView { get; set; } public ExtendedListView ListView { get; set; }
public StackLayout NoDataStackLayout { get; set; } public RedrawableStackLayout NoDataStackLayout { get; set; }
public StackLayout AddNewStackLayout { get; set; } public StackLayout AddNewStackLayout { get; set; }
public Label FileLabel { get; set; } public Label FileLabel { get; set; }
public ExtendedTableView NewTable { get; set; } public ExtendedTableView NewTable { get; set; }
@ -88,6 +88,7 @@ namespace Bit.App.Pages
EnableSelection = false, EnableSelection = false,
VerticalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start,
Margin = new Thickness(0, Helpers.OnPlatform(iOS: 10, Android: 30), 0, 0), Margin = new Thickness(0, Helpers.OnPlatform(iOS: 10, Android: 30), 0, 0),
WrappingStackLayout = () => NoDataStackLayout,
Root = new TableRoot Root = new TableRoot
{ {
new TableSection(AppResources.AddNewAttachment) new TableSection(AppResources.AddNewAttachment)
@ -122,7 +123,7 @@ namespace Bit.App.Pages
Style = (Style)Application.Current.Resources["text-muted"] Style = (Style)Application.Current.Resources["text-muted"]
}; };
NoDataStackLayout = new StackLayout NoDataStackLayout = new RedrawableStackLayout
{ {
VerticalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start,
Spacing = 0, Spacing = 0,

View File

@ -36,6 +36,7 @@ namespace Bit.App.Pages
} }
public ToolbarItem SaveToolbarItem { get; set; } public ToolbarItem SaveToolbarItem { get; set; }
public ToolbarItem CloseToolbarItem { get; set; }
public Label NoDataLabel { get; set; } public Label NoDataLabel { get; set; }
public TableSection FieldsSection { get; set; } public TableSection FieldsSection { get; set; }
public ExtendedTableView Table { get; set; } public ExtendedTableView Table { get; set; }
@ -131,12 +132,16 @@ namespace Bit.App.Pages
await DisplayAlert(null, AppResources.AnErrorHasOccurred, AppResources.Ok); await DisplayAlert(null, AppResources.AnErrorHasOccurred, AppResources.Ok);
} }
}, ToolbarItemOrder.Default, 0); }, ToolbarItemOrder.Default, 0);
ToolbarItems.Add(SaveToolbarItem);
Title = AppResources.CustomFields; Title = AppResources.CustomFields;
Content = Table; Content = Table;
if(Device.RuntimePlatform == Device.iOS) if(Device.RuntimePlatform == Device.iOS)
{ {
CloseToolbarItem = new DismissModalToolBarItem(this, AppResources.Close);
ToolbarItems.Add(CloseToolbarItem);
Table.RowHeight = -1; Table.RowHeight = -1;
Table.EstimatedRowHeight = 44; Table.EstimatedRowHeight = 44;
} }
@ -157,13 +162,14 @@ namespace Bit.App.Pages
return; return;
} }
if(_cipher.Fields != null && _cipher.Fields.Any()) var hasFields = _cipher.Fields?.Any() ?? false;
if(hasFields)
{ {
Content = Table; Content = Table;
ToolbarItems.Add(SaveToolbarItem); if(CloseToolbarItem != null)
if(Device.RuntimePlatform == Device.iOS)
{ {
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Cancel)); CloseToolbarItem.Text = AppResources.Cancel;
} }
foreach(var field in _cipher.Fields) foreach(var field in _cipher.Fields)
@ -213,9 +219,9 @@ namespace Bit.App.Pages
else else
{ {
Content = NoDataLabel; Content = NoDataLabel;
if(Device.RuntimePlatform == Device.iOS) if(ToolbarItems.Count > 0)
{ {
ToolbarItems.Add(new DismissModalToolBarItem(this, AppResources.Close)); ToolbarItems.RemoveAt(0);
} }
} }
} }

View File

@ -63,7 +63,7 @@ namespace Bit.iOS.Controls
private void SetSource() private void SetSource()
{ {
var view = (ExtendedTableView)Element; var view = (ExtendedTableView)Element;
if(view.NoFooter || view.NoHeader) if(true || view.NoFooter || view.NoHeader)
{ {
Control.Source = new CustomTableViewModelRenderer(view); Control.Source = new CustomTableViewModelRenderer(view);
} }
@ -116,6 +116,7 @@ namespace Bit.iOS.Controls
public class CustomTableViewModelRenderer : UnEvenTableViewModelRenderer public class CustomTableViewModelRenderer : UnEvenTableViewModelRenderer
{ {
private readonly ExtendedTableView _view; private readonly ExtendedTableView _view;
private bool _didRedraw = false;
public CustomTableViewModelRenderer(ExtendedTableView model) public CustomTableViewModelRenderer(ExtendedTableView model)
: base(model) : base(model)
@ -123,6 +124,16 @@ namespace Bit.iOS.Controls
_view = model; _view = model;
} }
public override async void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
// ref https://stackoverflow.com/a/48076188/1090359
if(!_didRedraw && _view.WrappingStackLayout != null)
{
_didRedraw = true;
await _view.WrappingStackLayout()?.RedrawIfNeededAsync(10, false);
}
}
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath) public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{ {
if(_view.HasUnevenRows) if(_view.HasUnevenRows)
@ -143,6 +154,16 @@ namespace Bit.iOS.Controls
return base.GetHeightForHeader(tableView, section); return base.GetHeightForHeader(tableView, section);
} }
public override UIView GetViewForHeader(UITableView tableView, nint section)
{
if(_view.NoHeader && section == 0)
{
return new UIView(new CGRect(0, 0, 0, 0));
}
return null;
}
public override nfloat GetHeightForFooter(UITableView tableView, nint section) public override nfloat GetHeightForFooter(UITableView tableView, nint section)
{ {
if(_view.NoFooter && (section + 1) == NumberOfSections(tableView)) if(_view.NoFooter && (section + 1) == NumberOfSections(tableView))
@ -152,6 +173,16 @@ namespace Bit.iOS.Controls
return 10f; return 10f;
} }
public override UIView GetViewForFooter(UITableView tableView, nint section)
{
if(_view.NoFooter && (section + 1) == NumberOfSections(tableView))
{
return new UIView(new CGRect(0, 0, 0, 0));
}
return null;
}
} }
} }
} }