[UItest] Added dynamic view gallery (#5402)
authorPavel Yakovlev <v-payako@microsoft.com>
Tue, 2 Apr 2019 02:45:41 +0000 (05:45 +0300)
committerShane Neuville <shane94@hotmail.com>
Tue, 2 Apr 2019 02:45:41 +0000 (20:45 -0600)
Xamarin.Forms.Controls/CoreGallery.cs
Xamarin.Forms.Controls/GalleryPages/DynamicViewGallery.cs [new file with mode: 0644]

index 54c8ef6..aad8e41 100644 (file)
@@ -342,6 +342,7 @@ namespace Xamarin.Forms.Controls
                                new GalleryPageFactory(() => new VisualGallery(), "Visual Gallery"),
                                new GalleryPageFactory(() => new WebViewCoreGalleryPage(), "WebView Gallery"),
                                new GalleryPageFactory(() => new WkWebViewCoreGalleryPage(), "WkWebView Gallery"),
+                               new GalleryPageFactory(() => new DynamicViewGallery(), "Dynamic ViewGallery"),
                                //pages
                                new GalleryPageFactory(() => new RootContentPage ("Content"), "RootPages Gallery"),
                                new GalleryPageFactory(() => new MasterDetailPageTabletPage(), "MasterDetailPage Tablet Page"),
diff --git a/Xamarin.Forms.Controls/GalleryPages/DynamicViewGallery.cs b/Xamarin.Forms.Controls/GalleryPages/DynamicViewGallery.cs
new file mode 100644 (file)
index 0000000..e8dbe31
--- /dev/null
@@ -0,0 +1,436 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Xamarin.Forms.Controls
+{
+       public class DynamicViewGallery : ContentPage
+       {
+               Dictionary<string, (Func<View> ctor, NamedAction[] methods)> _testedTypes;
+
+               HashSet<string> _exceptProperties = new HashSet<string>
+               {
+                       AutomationIdProperty.PropertyName,
+                       ClassIdProperty.PropertyName,
+                       "StyleId",
+               };
+
+               View _element;
+
+               StackLayout _propertyLayout;
+
+               StackLayout _pageContent;
+
+               Picker _selector;
+
+               public DynamicViewGallery()
+               {
+                       _testedTypes = new Dictionary<string, (Func<View> ctor, NamedAction[] methods)>
+                       {
+                               { nameof(ActivityIndicator), (() => new ActivityIndicator() { IsRunning = false }, null) },
+                               { nameof(ProgressBar), (() => new ProgressBar(), null) },
+                               { nameof(Button), (() => new Button { Text = "Button" }, null) },
+                               { nameof(Label), (() => new Label { Text = "label" }, null) },
+                               { nameof(Entry), (() => new Entry(), null) },
+                               { nameof(Editor), (() => new Editor(), null) },
+                               { nameof(Image), (() => new Image { Source = ImageSource.FromFile("cover1.jpg") }, null) },
+                               { nameof(ImageButton),(() => new ImageButton { Source = "bank.png"}, null) },
+                               { nameof(WebView), (() => new WebView(), null) },
+                               { nameof(SearchBar), (() => new SearchBar(), null) },
+                               { nameof(Stepper), (() => new Stepper(), null) },
+                               { nameof(Switch), (() => new Switch(), null) },
+                               { nameof(Picker), GetPicker()},
+                               { nameof(DatePicker), (() => new DatePicker(), null) },
+                               { nameof(TimePicker), (() => new TimePicker(), null) },
+                               { nameof(ListView), (() => new ListView(), null) },
+                               { nameof(BoxView), (() => new BoxView(), null) },
+                       };
+
+                       _selector = new Picker();
+                       foreach (var item in _testedTypes)
+                               _selector.Items.Add(item.Key.ToString());
+                       _selector.SelectedIndexChanged += TypeSelected;
+
+                       var selectorGrid = new Grid
+                       {
+                               Padding = 0,
+                               ColumnSpacing = 6,
+                               RowSpacing = 6,
+                               MinimumHeightRequest = 40,
+                               ColumnDefinitions = {
+                                       new ColumnDefinition { Width = 150 },
+                                       new ColumnDefinition { Width = GridLength.Star }
+                               }
+                       };
+                       selectorGrid.AddChild(new Label { Text = "Control:" }, 0, 0);
+                       selectorGrid.AddChild(_selector, 1, 0);
+
+                       _propertyLayout = new StackLayout
+                       {
+                               Spacing = 10,
+                               Padding = 10
+                       };
+
+                       Content = _pageContent = new StackLayout
+                       {
+                               Padding = 10,
+                               Spacing = 10,
+                               Children =
+                               {
+                                       selectorGrid,
+                                       new ScrollView
+                                       {
+                                               Margin = new Thickness(-10, 0),
+                                               Content = _propertyLayout
+                                       },
+                                       new BoxView
+                                       {
+                                               HeightRequest = 1,
+                                               Margin = new Thickness(-10, 0),
+                                               Color = Color.Black
+                                       }
+                               }
+                       };
+               }
+
+               void OnElementUpdated(View oldElement)
+               {
+                       if (oldElement != null)
+                               _pageContent.Children.Remove(oldElement);
+
+                       _propertyLayout.Children.Clear();
+
+                       if (_element == null)
+                               return;
+
+                       var elementType = _element.GetType();
+
+                       var publicProperties = elementType
+                               .GetProperties(BindingFlags.Public | BindingFlags.Instance)
+                               .Where(p => p.CanRead && p.CanWrite && !_exceptProperties.Contains(p.Name));
+
+                       // BindableProperty used to clean property values
+                       var bindableProperties = elementType
+                               .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
+                               .Where(p => p.FieldType.IsAssignableFrom(typeof(BindableProperty)))
+                               .Select(p => (BindableProperty)p.GetValue(_element));
+
+                       foreach (var property in publicProperties)
+                       {
+                               if (property.PropertyType == typeof(Color))
+                               {
+                                       var colorPicker = new ColorPicker
+                                       {
+                                               Title = property.Name,
+                                               Color = (Color)property.GetValue(_element)
+                                       };
+                                       colorPicker.ColorPicked += (_, e) => property.SetValue(_element, e.Color);
+                                       _propertyLayout.Children.Add(colorPicker);
+                               }
+                               else if (property.PropertyType == typeof(string))
+                               {
+                                       _propertyLayout.Children.Add(CreateStringPicker(property));
+                               }
+                               else if (property.PropertyType == typeof(double) ||
+                                       property.PropertyType == typeof(float) ||
+                                       property.PropertyType == typeof(int))
+                               {
+                                       _propertyLayout.Children.Add(
+                                               CreateValuePicker(property, bindableProperties.FirstOrDefault(p => p.PropertyName == property.Name)));
+                               }
+                               else if (property.PropertyType == typeof(bool))
+                               {
+                                       _propertyLayout.Children.Add(CreateBooleanPicker(property));
+                               }
+                               else if (property.PropertyType == typeof(Thickness))
+                               {
+                                       _propertyLayout.Children.Add(CreateThicknessPicker(property));
+                               }
+                               else
+                               {
+                                       //_propertyLayout.Children.Add(new Label { Text = $"//TODO: {property.Name} ({property.PropertyType})", TextColor = Color.Gray });
+                               }
+                       }
+
+                       var customMethods = _testedTypes[elementType.Name].methods;
+                       if (customMethods != null)
+                       {
+                               _propertyLayout.Children.Add(new Label {
+                                       Text = "Custom methods",
+                                       FontSize = 20,
+                                       Margin = 6
+                               });
+
+                               foreach (var method in customMethods)
+                               {
+                                       _propertyLayout.Children.Add(new Button
+                                       {
+                                               Text = method.Name,
+                                               FontAttributes = FontAttributes.Bold,
+                                               Padding = 6,
+                                               Command = new Command(() => method.Action(_element))
+                                       });
+                               }
+                       }
+
+                       _pageContent.Children.Add(_element);
+               }
+
+               void TypeSelected(object sender, EventArgs e)
+               {
+                       var oldElement = _element;
+                       try
+                       {
+                               _element = _testedTypes[(string)_selector.SelectedItem].ctor();
+                       }
+                       catch
+                       {
+                               _element = null;
+                       }
+                       OnElementUpdated(oldElement);
+               }
+
+               Dictionary<string, (double min, double max)> _minMaxProperties = new Dictionary<string, (double min, double max)>
+               {
+                       { ScaleProperty.PropertyName, (0d, 1d) },
+                       { ScaleXProperty.PropertyName, (0d, 1d) },
+                       { ScaleYProperty.PropertyName, (0d, 1d) },
+                       { OpacityProperty.PropertyName, (0d, 1d) },
+                       { RotationProperty.PropertyName, (0d, 360d) },
+                       { RotationXProperty.PropertyName, (0d, 360d) },
+                       { RotationYProperty.PropertyName, (0d, 360d) },
+                       { View.MarginProperty.PropertyName, (-100, 100) },
+                       { PaddingElement.PaddingProperty.PropertyName, (-100, 100) },
+               };
+
+               Grid CreateValuePicker(PropertyInfo property, BindableProperty bindableProperty)
+               {
+                       var min = 0d;
+                       var max = 100d;
+                       if (_minMaxProperties.ContainsKey(property.Name))
+                       {
+                               min = _minMaxProperties[property.Name].min;
+                               max = _minMaxProperties[property.Name].max;
+                       }
+
+                       var isInt = property.PropertyType == typeof(int);
+                       var value = isInt ? (int)property.GetValue(_element) : (double)property.GetValue(_element);
+                       var slider = new Slider(min, max, value);
+
+                       var actions = new Grid
+                       {
+                               Padding = 0,
+                               ColumnSpacing = 6,
+                               RowSpacing = 6,
+                               ColumnDefinitions =
+                               {
+                                       new ColumnDefinition { Width = GridLength.Star },
+                                       new ColumnDefinition { Width = 40 }
+                               }
+                       };
+
+                       actions.AddChild(new Label { Text = property.Name, FontAttributes = FontAttributes.Bold }, 0, 0, 2);
+
+                       if (bindableProperty != null)
+                       {
+                               actions.AddChild(new Button
+                               {
+                                       Text = "X",
+                                       TextColor = Color.White,
+                                       BackgroundColor = Color.DarkRed,
+                                       WidthRequest = 28,
+                                       HeightRequest = 28,
+                                       Margin = 0,
+                                       Padding = 0,
+                                       Command = new Command(() => _element.ClearValue(bindableProperty))
+                               }, 1, 0);
+                       }
+
+                       var valueLabel = new Label
+                       {
+                               Text = slider.Value.ToString(isInt ? "0" : "0.#"),
+                               HorizontalOptions = LayoutOptions.End
+                       };
+
+                       slider.ValueChanged += (_, e) =>
+                       {
+                               if (isInt)
+                                       property.SetValue(_element, (int)e.NewValue);
+                               else
+                                       property.SetValue(_element, e.NewValue);
+                               valueLabel.Text = e.NewValue.ToString(isInt ? "0" : "0.#");
+                       };
+
+                       actions.AddChild(slider, 0, 1);
+                       actions.AddChild(valueLabel, 1, 1);
+
+                       return actions;
+               }
+
+               Grid CreateThicknessPicker(PropertyInfo property)
+               {
+                       var grid = new Grid
+                       {
+                               Padding = 0,
+                               RowSpacing = 3,
+                               ColumnSpacing = 3,
+                               ColumnDefinitions =
+                                               {
+                                                       new ColumnDefinition { Width = 50 },
+                                                       new ColumnDefinition { Width = GridLength.Star },
+                                                       new ColumnDefinition { Width = 30 }
+                                               },
+                       };
+                       grid.AddChild(new Label { Text = property.Name, FontAttributes = FontAttributes.Bold }, 0, 0, 2);
+
+                       var val = (Thickness)property.GetValue(_element);
+                       var sliders = new Slider[4];
+                       var valueLabels = new Label[4];
+                       for (int i = 0; i < 4; i++)
+                       {
+                               sliders[i] = new Slider
+                               {
+                                       VerticalOptions = LayoutOptions.Center,
+                                       Minimum = 0,
+                                       Maximum = 100
+                               };
+                               var row = i + 1;
+                               switch (i)
+                               {
+                                       case 0:
+                                               sliders[i].Value = val.Left;
+                                               grid.AddChild(new Label { Text = nameof(val.Left) }, 0, row);
+                                               break;
+                                       case 1:
+                                               sliders[i].Value = val.Top;
+                                               grid.AddChild(new Label { Text = nameof(val.Top) }, 0, row);
+                                               break;
+                                       case 2:
+                                               sliders[i].Value = val.Right;
+                                               grid.AddChild(new Label { Text = nameof(val.Right) }, 0, row);
+                                               break;
+                                       case 3:
+                                               sliders[i].Value = val.Bottom;
+                                               grid.AddChild(new Label { Text = nameof(val.Bottom) }, 0, row);
+                                               break;
+                               }
+
+                               valueLabels[i] = new Label { Text = sliders[i].Value.ToString("0") };
+                               grid.AddChild(sliders[i], 1, row);
+                               grid.AddChild(valueLabels[i], 2, row);
+                               sliders[i].ValueChanged += ThicknessChanged;
+                       }
+
+                       void ThicknessChanged(object sender, ValueChangedEventArgs e)
+                       {
+                               property.SetValue(_element, new Thickness(sliders[0].Value, sliders[1].Value, sliders[2].Value, sliders[3].Value));
+                               for (int i = 0; i < valueLabels.Length; i++)
+                                       valueLabels[i].Text = sliders[i].Value.ToString("0");
+                       }
+
+                       return grid;
+               }
+
+               Grid CreateBooleanPicker(PropertyInfo property)
+               {
+                       var grid = new Grid
+                       {
+                               Padding = 0,
+                               ColumnSpacing = 6,
+                               RowSpacing = 6,
+                               ColumnDefinitions =
+                                               {
+                                                       new ColumnDefinition { Width = GridLength.Star },
+                                                       new ColumnDefinition { Width = 50 }
+                                               }
+                       };
+                       grid.AddChild(new Label { Text = property.Name, FontAttributes = FontAttributes.Bold }, 0, 0);
+                       var boolSwitch = new Switch
+                       {
+                               IsToggled = (bool)property.GetValue(_element),
+                               HorizontalOptions = LayoutOptions.Center,
+                               VerticalOptions = LayoutOptions.Center
+                       };
+                       boolSwitch.Toggled += (_, e) => property.SetValue(_element, e.Value);
+                       grid.AddChild(boolSwitch, 1, 0);
+                       _element.PropertyChanged += (_, e) =>
+                       {
+                               if (e.PropertyName == property.Name)
+                               {
+                                       var newVal = (bool)property.GetValue(_element);
+                                       if (newVal != boolSwitch.IsToggled)
+                                               boolSwitch.IsToggled = newVal;
+                               }
+                       };
+
+                       return grid;
+               }
+
+               Grid CreateStringPicker(PropertyInfo property)
+               {
+                       var grid = new Grid
+                       {
+                               Padding = 0,
+                               ColumnSpacing = 6,
+                               RowSpacing = 6
+                       };
+                       grid.AddChild(new Label { Text = property.Name, FontAttributes = FontAttributes.Bold }, 0, 0);
+                       var entry = new Entry
+                       {
+                               Text = (string)property.GetValue(_element),
+                               HorizontalOptions = LayoutOptions.FillAndExpand,
+                               VerticalOptions = LayoutOptions.FillAndExpand
+                       };
+                       entry.TextChanged += (_, e) => property.SetValue(_element, e.NewTextValue);
+                       grid.AddChild(entry, 0, 1);
+                       _element.PropertyChanged += (_, e) =>
+                       {
+                               if (e.PropertyName == property.Name)
+                               {
+                                       var newVal = (string)property.GetValue(_element);
+                                       if (newVal != entry.Text)
+                                               entry.Text = newVal;
+                               }
+                       };
+
+                       return grid;
+               }
+
+               class NamedAction
+               {
+                       public string Name { get; set; }
+
+                       public Action<View> Action { get; set; }
+               }
+
+               (Func<View> ctor, NamedAction[] methods) GetPicker()
+               {
+                       return (ctor: () =>
+                       {
+                               var picker = new Picker();
+                               picker.Items.Add("item 1");
+                               picker.Items.Add("item 2");
+                               return picker;
+                       }, methods: new[] {
+                                       new NamedAction {
+                                               Name = "Add item",
+                                               Action = (p) => (p as Picker).Items.Add("item")
+                                       },
+                                       new NamedAction {
+                                               Name = "Remove item last item",
+                                               Action = (p) => {
+                                                       var picker = (Picker)p;
+                                                       if (picker.Items.Count > 0)
+                                                               picker.Items.RemoveAt(picker.Items.Count - 1);
+                                               }
+                                       },
+                                       new NamedAction {
+                                               Name = "Clear",
+                                               Action = (p) => (p as Picker).Items.Clear()
+                                       }
+                               }
+                       );
+               }
+       }
+}