diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj index 0bad52e06..9896a4d75 100644 --- a/src/Android/Android.csproj +++ b/src/Android/Android.csproj @@ -259,6 +259,7 @@ + diff --git a/src/Android/MainApplication.cs b/src/Android/MainApplication.cs index deb3a6c39..e04ee560d 100644 --- a/src/Android/MainApplication.cs +++ b/src/Android/MainApplication.cs @@ -122,6 +122,7 @@ namespace Bit.Android .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) + .RegisterType(new ContainerControlledLifetimeManager()) // Repositories .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) diff --git a/src/Android/Services/ReflectionService.cs b/src/Android/Services/ReflectionService.cs new file mode 100644 index 000000000..4685f4c13 --- /dev/null +++ b/src/Android/Services/ReflectionService.cs @@ -0,0 +1,34 @@ +using System; +using System.Reflection; +using Bit.App.Abstractions; +using Bit.App.Controls; +using Xamarin.Forms; + +namespace Bit.Android.Services +{ + public class ReflectionService : IReflectionService + { + public Func GetVisualElementOnSizeRequest(ExtendedTableView tableView) + { + var handle = typeof(VisualElement).GetMethod( + "OnSizeRequest", + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new Type[] { typeof(double), typeof(double) }, + null)?.MethodHandle; + + if(!handle.HasValue) + { + throw new ArgumentNullException("handle could not be found."); + } + + var pointer = handle.Value.GetFunctionPointer(); + if(pointer == null) + { + throw new ArgumentNullException("pointer could not be found."); + } + + return (Func)Activator.CreateInstance(typeof(Func), tableView, pointer); + } + } +} diff --git a/src/App/Abstractions/Services/IReflectionService.cs b/src/App/Abstractions/Services/IReflectionService.cs new file mode 100644 index 000000000..eae6232a8 --- /dev/null +++ b/src/App/Abstractions/Services/IReflectionService.cs @@ -0,0 +1,11 @@ +using System; +using Bit.App.Controls; +using Xamarin.Forms; + +namespace Bit.App.Abstractions +{ + public interface IReflectionService + { + Func GetVisualElementOnSizeRequest(ExtendedTableView tableView); + } +} diff --git a/src/App/App.csproj b/src/App/App.csproj index 595fb610d..7faf81742 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -40,6 +40,7 @@ + diff --git a/src/App/Controls/ExtendedTableView.cs b/src/App/Controls/ExtendedTableView.cs index 550fcad3f..ced2510fe 100644 --- a/src/App/Controls/ExtendedTableView.cs +++ b/src/App/Controls/ExtendedTableView.cs @@ -1,10 +1,21 @@ using System; using Xamarin.Forms; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using XLabs.Ioc; +using Bit.App.Abstractions; namespace Bit.App.Controls { public class ExtendedTableView : TableView { + public ExtendedTableView() + : base() + { + VerticalOptions = LayoutOptions.Start; + } + public static readonly BindableProperty EnableScrollingProperty = BindableProperty.Create(nameof(EnableScrolling), typeof(bool), typeof(ExtendedTableView), true); @@ -33,5 +44,17 @@ namespace Bit.App.Controls } public int EstimatedRowHeight { get; set; } + + protected override SizeRequest OnSizeRequest(double widthConstraint, double heightConstraint) + { + if(Device.OS == TargetPlatform.iOS && VerticalOptions.Alignment != LayoutAlignment.Fill) + { + var reflectionService = Resolver.Resolve(); + var baseBaseOnSizeRequest = reflectionService.GetVisualElementOnSizeRequest(this); + return baseBaseOnSizeRequest(widthConstraint, heightConstraint); + } + + return base.OnSizeRequest(widthConstraint, heightConstraint); + } } } diff --git a/src/App/Pages/Settings/SettingsEditFolderPage.cs b/src/App/Pages/Settings/SettingsEditFolderPage.cs index 5ebc7044e..b78f322fe 100644 --- a/src/App/Pages/Settings/SettingsEditFolderPage.cs +++ b/src/App/Pages/Settings/SettingsEditFolderPage.cs @@ -47,6 +47,9 @@ namespace Bit.App.Pages EnableScrolling = false, EnableSelection = false, HasUnevenRows = true, + VerticalOptions = LayoutOptions.Start, + BackgroundColor = Color.Gray, + Margin = new Thickness(0, -1), Root = new TableRoot { new TableSection() @@ -67,6 +70,9 @@ namespace Bit.App.Pages Intent = TableIntent.Settings, EnableScrolling = false, EnableSelection = true, + VerticalOptions = LayoutOptions.End, + BackgroundColor = Color.Yellow, + Margin = new Thickness(0, -1), Root = new TableRoot { new TableSection() @@ -102,7 +108,7 @@ namespace Bit.App.Pages }, ToolbarItemOrder.Default, 0); Title = "Edit Folder"; - Content = new StackLayout { Children = { mainTable, deleteTable } }; + Content = new ScrollView { Content = new StackLayout { Children = { mainTable, deleteTable } } }; ToolbarItems.Add(saveToolBarItem); if(Device.OS == TargetPlatform.iOS) { diff --git a/src/App/Pages/Tools/ToolsPasswordGeneratorPage.cs b/src/App/Pages/Tools/ToolsPasswordGeneratorPage.cs index c49f8afc7..35ad9d460 100644 --- a/src/App/Pages/Tools/ToolsPasswordGeneratorPage.cs +++ b/src/App/Pages/Tools/ToolsPasswordGeneratorPage.cs @@ -39,7 +39,8 @@ namespace Bit.App.Pages Margin = new Thickness(15, 40, 15, 0), HorizontalTextAlignment = TextAlignment.Center, FontFamily = "Courier", - LineBreakMode = LineBreakMode.TailTruncation + LineBreakMode = LineBreakMode.TailTruncation, + VerticalOptions = LayoutOptions.Start }; var tgr = new TapGestureRecognizer(); @@ -64,6 +65,7 @@ namespace Bit.App.Pages EnableScrolling = false, Intent = TableIntent.Menu, HasUnevenRows = true, + VerticalOptions = LayoutOptions.End, Root = new TableRoot { new TableSection diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs index b20e9aea7..6aacf26c4 100644 --- a/src/iOS/AppDelegate.cs +++ b/src/iOS/AppDelegate.cs @@ -200,6 +200,7 @@ namespace Bit.iOS .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) + .RegisterType(new ContainerControlledLifetimeManager()) // Repositories .RegisterType(new ContainerControlledLifetimeManager()) .RegisterType(new ContainerControlledLifetimeManager()) diff --git a/src/iOS/Controls/ExtendedTableViewRenderer.cs b/src/iOS/Controls/ExtendedTableViewRenderer.cs index 33b9a5fd8..1f35bc0b5 100644 --- a/src/iOS/Controls/ExtendedTableViewRenderer.cs +++ b/src/iOS/Controls/ExtendedTableViewRenderer.cs @@ -23,9 +23,12 @@ namespace Bit.iOS.Controls UpdateRowHeight(view); UpdateEstimatedRowHeight(view); UpdateSeparatorColor(view); + + Control.SectionFooterHeight = 0.01f; + Control.EstimatedSectionFooterHeight = 1f; + Control.ContentInset = new UIEdgeInsets(0, 0, -35, 0); } } - protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); diff --git a/src/iOS/Services/ReflectionService.cs b/src/iOS/Services/ReflectionService.cs new file mode 100644 index 000000000..142721485 --- /dev/null +++ b/src/iOS/Services/ReflectionService.cs @@ -0,0 +1,34 @@ +using System; +using System.Reflection; +using Bit.App.Abstractions; +using Bit.App.Controls; +using Xamarin.Forms; + +namespace Bit.iOS.Services +{ + public class ReflectionService : IReflectionService + { + public Func GetVisualElementOnSizeRequest(ExtendedTableView tableView) + { + var handle = typeof(VisualElement).GetMethod( + "OnSizeRequest", + BindingFlags.Instance | BindingFlags.NonPublic, + null, + new Type[] { typeof(double), typeof(double) }, + null)?.MethodHandle; + + if(!handle.HasValue) + { + throw new ArgumentNullException("handle could not be found."); + } + + var pointer = handle.Value.GetFunctionPointer(); + if(pointer == null) + { + throw new ArgumentNullException("pointer could not be found."); + } + + return (Func)Activator.CreateInstance(typeof(Func), tableView, pointer); + } + } +} diff --git a/src/iOS/iOS.csproj b/src/iOS/iOS.csproj index a67c1aada..a24ae40f0 100644 --- a/src/iOS/iOS.csproj +++ b/src/iOS/iOS.csproj @@ -115,6 +115,7 @@ +