зеркало из https://github.com/DeGsoft/maui-linux.git
Merge branch '4.4.0'
This commit is contained in:
Коммит
1b9c22b4b9
|
@ -390,14 +390,22 @@ namespace Xamarin.Forms.Build.Tasks
|
||||||
public static TypeReference ResolveGenericParameters(this TypeReference self, TypeReference declaringTypeReference)
|
public static TypeReference ResolveGenericParameters(this TypeReference self, TypeReference declaringTypeReference)
|
||||||
{
|
{
|
||||||
var genericdeclType = declaringTypeReference as GenericInstanceType;
|
var genericdeclType = declaringTypeReference as GenericInstanceType;
|
||||||
if (genericdeclType == null)
|
var genericParameterSelf = self as GenericParameter;
|
||||||
|
var genericself = self as GenericInstanceType;
|
||||||
|
|
||||||
|
if (genericdeclType == null && genericParameterSelf == null && genericself == null)
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
var genericParameterSelf = self as GenericParameter;
|
if (genericdeclType == null && genericParameterSelf!=null)
|
||||||
|
{
|
||||||
|
var typeDef = declaringTypeReference.Resolve();
|
||||||
|
if (typeDef.BaseType == null || typeDef.BaseType.FullName == "System.Object")
|
||||||
|
return self;
|
||||||
|
return self.ResolveGenericParameters(typeDef.BaseType.ResolveGenericParameters(declaringTypeReference));
|
||||||
|
}
|
||||||
if (genericParameterSelf != null)
|
if (genericParameterSelf != null)
|
||||||
return genericdeclType.GenericArguments[genericParameterSelf.Position];
|
return genericdeclType.GenericArguments[genericParameterSelf.Position];
|
||||||
|
|
||||||
var genericself = self as GenericInstanceType;
|
|
||||||
if (genericself != null)
|
if (genericself != null)
|
||||||
return genericself.ResolveGenericParameters(declaringTypeReference);
|
return genericself.ResolveGenericParameters(declaringTypeReference);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Text;
|
||||||
|
using Xamarin.Forms.CustomAttributes;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
using Xamarin.UITest;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Xamarin.Forms.Core.UITests;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Controls.Issues
|
||||||
|
{
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
[Issue(IssueTracker.Github, 8262, "[Android] ImageRenderer still being accessed after control destroyed",
|
||||||
|
PlatformAffected.Android)]
|
||||||
|
#if UITEST
|
||||||
|
[NUnit.Framework.Category(UITestCategories.LifeCycle)]
|
||||||
|
[NUnit.Framework.Category(UITestCategories.CollectionView)]
|
||||||
|
#endif
|
||||||
|
public class Issue8262 : TestContentPage
|
||||||
|
{
|
||||||
|
public View WithBounds(View v, double x, double y, double w, double h)
|
||||||
|
{
|
||||||
|
AbsoluteLayout.SetLayoutBounds(v, new Rectangle(x, y, w, h));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Init()
|
||||||
|
{
|
||||||
|
IEnumerable<View> Select((string groupHeader, IEnumerable<int> items) t)
|
||||||
|
{
|
||||||
|
yield return new AbsoluteLayout
|
||||||
|
{
|
||||||
|
Children = {
|
||||||
|
WithBounds(new Label {
|
||||||
|
Text = t.groupHeader, HorizontalTextAlignment = TextAlignment.Center,
|
||||||
|
TextColor = Color.FromUint(0xff5a5a5a), FontSize = 10
|
||||||
|
}, 0, 21.1, 310, AbsoluteLayout.AutoSize) },
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
VerticalOptions = LayoutOptions.Start,
|
||||||
|
HeightRequest = 46
|
||||||
|
};
|
||||||
|
foreach (var item in t.items)
|
||||||
|
{
|
||||||
|
yield return new AbsoluteLayout
|
||||||
|
{
|
||||||
|
Children = {
|
||||||
|
|
||||||
|
WithBounds(new Image { Source = ImageSource.FromResource("Xamarin.Forms.Controls.GalleryPages.crimson.jpg", System.Reflection.Assembly.GetCallingAssembly()) }, 23.6, 14.5, 14.9, 20.7),
|
||||||
|
|
||||||
|
WithBounds(new Label { Text = item.ToString(), TextColor = Color.FromUint(0xff5a5a5a), FontSize = 10 }, 58, 18.2, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize)
|
||||||
|
},
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
VerticalOptions = LayoutOptions.Start,
|
||||||
|
HeightRequest = 49.7
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Content = new AbsoluteLayout
|
||||||
|
{
|
||||||
|
Children = {
|
||||||
|
new CollectionView {
|
||||||
|
ItemsSource =
|
||||||
|
new (string, Func<int, bool>)[] {
|
||||||
|
("odd", i => i % 2 == 1),
|
||||||
|
("even", i => i % 2 == 0),
|
||||||
|
("triple", i => i % 3 == 0),
|
||||||
|
("fives", i => i % 5 == 0) }
|
||||||
|
.Select(t => (t.Item1, Enumerable.Range(1, 100).Where(t.Item2)))
|
||||||
|
.SelectMany(Select),
|
||||||
|
ItemTemplate = new DataTemplate(() => {
|
||||||
|
var template = new ContentView();
|
||||||
|
template.SetBinding(ContentView.ContentProperty, ".");
|
||||||
|
return template;
|
||||||
|
}),
|
||||||
|
ItemsLayout = LinearItemsLayout.Vertical,
|
||||||
|
ItemSizingStrategy = ItemSizingStrategy.MeasureFirstItem,
|
||||||
|
AutomationId = "ScrollMe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
[Test]
|
||||||
|
public void ScrollingQuicklyOnCollectionViewDoesntCrashOnDestroyedImage()
|
||||||
|
{
|
||||||
|
RunningApp.WaitForElement("ScrollMe");
|
||||||
|
RunningApp.ScrollDown("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
|
||||||
|
RunningApp.ScrollUp("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
|
||||||
|
RunningApp.ScrollDown("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
|
||||||
|
RunningApp.ScrollUp("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
|
||||||
|
RunningApp.ScrollDown("ScrollMe", ScrollStrategy.Gesture, swipeSpeed: 20000);
|
||||||
|
RunningApp.WaitForElement("ScrollMe");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
using Xamarin.Forms.CustomAttributes;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Xamarin.Forms.Core.UITests;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Controls.Issues
|
||||||
|
{
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
[Issue(IssueTracker.Github, 8461, "[Bug] [iOS] [Shell] \"Nav Stack consistency error\"",
|
||||||
|
PlatformAffected.iOS)]
|
||||||
|
#if UITEST
|
||||||
|
[NUnit.Framework.Category(UITestCategories.Shell)]
|
||||||
|
[NUnit.Framework.Category(UITestCategories.Navigation)]
|
||||||
|
#endif
|
||||||
|
public class Issue8461 : TestShell
|
||||||
|
{
|
||||||
|
const string ButtonId = "PageButtonId";
|
||||||
|
const string LayoutId = "LayoutId";
|
||||||
|
|
||||||
|
protected override void Init()
|
||||||
|
{
|
||||||
|
var page1 = CreateContentPage("page 1");
|
||||||
|
var page2 = new ContentPage() { Title = "page 2" };
|
||||||
|
|
||||||
|
var pushPageBtn = new Button();
|
||||||
|
pushPageBtn.Text = "Push Page";
|
||||||
|
pushPageBtn.AutomationId = ButtonId;
|
||||||
|
pushPageBtn.Clicked += (sender, args) =>
|
||||||
|
{
|
||||||
|
Navigation.PushAsync(page2);
|
||||||
|
};
|
||||||
|
|
||||||
|
page1.Content = new StackLayout()
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
pushPageBtn
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var instructions = new StackLayout()
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new Label()
|
||||||
|
{
|
||||||
|
Text = "1. Swipe left to dismiss this page, but cancel the gesture before it completes"
|
||||||
|
},
|
||||||
|
new Label()
|
||||||
|
{
|
||||||
|
Text = "2. Swipe left to dismiss this page again, crashes immediately"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Grid.SetColumn(instructions, 1);
|
||||||
|
|
||||||
|
page2.Content = new Grid()
|
||||||
|
{
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
VerticalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
|
||||||
|
ColumnDefinitions = new ColumnDefinitionCollection()
|
||||||
|
{
|
||||||
|
new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },
|
||||||
|
new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) },
|
||||||
|
},
|
||||||
|
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
// Use this BoxView to achor our swipe to left of the screen
|
||||||
|
new BoxView()
|
||||||
|
{
|
||||||
|
AutomationId = LayoutId,
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
VerticalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
BackgroundColor = Color.Red
|
||||||
|
},
|
||||||
|
instructions
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UITEST && __IOS__
|
||||||
|
[Test]
|
||||||
|
public void ShellSwipeToDismiss()
|
||||||
|
{
|
||||||
|
var pushButton = RunningApp.WaitForElement(ButtonId);
|
||||||
|
Assert.AreEqual(1, pushButton.Length);
|
||||||
|
|
||||||
|
RunningApp.Tap(ButtonId);
|
||||||
|
|
||||||
|
var page2Layout = RunningApp.WaitForElement(LayoutId);
|
||||||
|
Assert.AreEqual(1, page2Layout.Length);
|
||||||
|
// Swipe in from left across 1/2 of screen width
|
||||||
|
RunningApp.SwipeLeftToRight(LayoutId, 0.99, 500, false);
|
||||||
|
// Swipe in from left across full screen width
|
||||||
|
RunningApp.SwipeLeftToRight(0.99, 500);
|
||||||
|
|
||||||
|
pushButton = RunningApp.WaitForElement(ButtonId);
|
||||||
|
Assert.AreEqual(1, pushButton.Length);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Xamarin.Forms.CustomAttributes;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Controls.Issues
|
||||||
|
{
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
[Issue(IssueTracker.Github, 8644, "WPF Entry crashes when IsPassword=true", PlatformAffected.WPF)]
|
||||||
|
public class Issue8644 : TestContentPage
|
||||||
|
{
|
||||||
|
public class BinCon : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
string _title;
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get => _title;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_title = value?.Length > 4 ? value.Substring(0, 4) : value;
|
||||||
|
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
protected override void Init()
|
||||||
|
{
|
||||||
|
var bc = new BinCon();
|
||||||
|
var e1 = new Entry
|
||||||
|
{
|
||||||
|
BindingContext = bc,
|
||||||
|
Margin = new Thickness(50),
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
IsPassword = true,
|
||||||
|
};
|
||||||
|
e1.SetBinding(Entry.TextProperty, nameof(BinCon.Title));
|
||||||
|
|
||||||
|
// Label just to show current Entry text, not needed for test
|
||||||
|
var lbl = new Label { BindingContext = bc };
|
||||||
|
lbl.SetBinding(Label.TextProperty, nameof(BinCon.Title));
|
||||||
|
var stack = new StackLayout
|
||||||
|
{
|
||||||
|
|
||||||
|
Children = {
|
||||||
|
new Label { Text = "Type more than 4 symbols" },
|
||||||
|
e1,
|
||||||
|
lbl,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Content = stack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
using Xamarin.Forms.CustomAttributes;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
using Xamarin.Forms.Core.UITests;
|
||||||
|
using Xamarin.UITest;
|
||||||
|
using NUnit.Framework;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Controls.Issues
|
||||||
|
{
|
||||||
|
#if UITEST
|
||||||
|
[NUnit.Framework.Category(UITestCategories.Shell)]
|
||||||
|
#endif
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
[Issue(IssueTracker.Github, 8741, "[Bug] [Shell] [Android] ToolbarItem Enabled/Disabled behavior does not work for Shell apps", PlatformAffected.Android)]
|
||||||
|
public class Issue8741 : TestShell
|
||||||
|
{
|
||||||
|
protected override void Init()
|
||||||
|
{
|
||||||
|
var page = CreateContentPage();
|
||||||
|
var toolbarItem = new ToolbarItem
|
||||||
|
{
|
||||||
|
Text = "Add",
|
||||||
|
AutomationId = "Add"
|
||||||
|
};
|
||||||
|
|
||||||
|
toolbarItem.SetBinding(MenuItem.CommandProperty, "ToolbarTappedCommand");
|
||||||
|
page.ToolbarItems.Add(toolbarItem);
|
||||||
|
|
||||||
|
var button = new Button
|
||||||
|
{
|
||||||
|
Text = "Toggle Enabled/Disabled",
|
||||||
|
AutomationId = "ToggleEnabled"
|
||||||
|
};
|
||||||
|
|
||||||
|
button.SetBinding(Button.CommandProperty, "ChangeToggleCommand");
|
||||||
|
var label = new Label();
|
||||||
|
label.SetBinding(Label.TextProperty, "EnabledText");
|
||||||
|
|
||||||
|
var clickCount = new Label();
|
||||||
|
clickCount.AutomationId = "ClickCount";
|
||||||
|
clickCount.SetBinding(Label.TextProperty, "ClickCount");
|
||||||
|
|
||||||
|
page.Content =
|
||||||
|
new StackLayout
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
label,
|
||||||
|
clickCount,
|
||||||
|
button
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BindingContext = new ViewModelIssue8741();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
[Test]
|
||||||
|
public void Issue8741Test()
|
||||||
|
{
|
||||||
|
RunningApp.WaitForElement("Add");
|
||||||
|
RunningApp.Tap("Add");
|
||||||
|
#if __ANDROID__
|
||||||
|
var toolbarItemColorValue = GetToolbarItemColorValue();
|
||||||
|
int disabledAlpha = GetAlphaValue(toolbarItemColorValue);
|
||||||
|
#endif
|
||||||
|
Assert.AreEqual("0", RunningApp.WaitForElement("ClickCount")[0].ReadText());
|
||||||
|
|
||||||
|
RunningApp.Tap("ToggleEnabled");
|
||||||
|
RunningApp.Tap("Add");
|
||||||
|
#if __ANDROID__
|
||||||
|
toolbarItemColorValue = GetToolbarItemColorValue();
|
||||||
|
int enabledAlpha = GetAlphaValue(toolbarItemColorValue);
|
||||||
|
Assert.Less(disabledAlpha, enabledAlpha);
|
||||||
|
#endif
|
||||||
|
Assert.AreEqual("1", RunningApp.WaitForElement("ClickCount")[0].ReadText());
|
||||||
|
|
||||||
|
RunningApp.Tap("ToggleEnabled");
|
||||||
|
RunningApp.Tap("Add");
|
||||||
|
|
||||||
|
Assert.AreEqual("1", RunningApp.WaitForElement("ClickCount")[0].ReadText());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __ANDROID__
|
||||||
|
private object GetToolbarItemColorValue()
|
||||||
|
{
|
||||||
|
return RunningApp.Query(x => x.Text("Add").Invoke("getCurrentTextColor"))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetAlphaValue(object toolbarItemColorValue)
|
||||||
|
{
|
||||||
|
int color = Convert.ToInt32(toolbarItemColorValue);
|
||||||
|
int a = (color >> 24) & 0xff;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
public class ViewModelIssue8741 : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
bool _canAddNewItem;
|
||||||
|
int _clickCount;
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Enabled
|
||||||
|
{
|
||||||
|
get => _canAddNewItem;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_canAddNewItem = value;
|
||||||
|
OnPropertyChanged(nameof(Enabled));
|
||||||
|
ToolbarTappedCommand.ChangeCanExecute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ClickCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _clickCount;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_clickCount = value;
|
||||||
|
OnPropertyChanged(nameof(ClickCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EnabledText { get; set; }
|
||||||
|
public Command ChangeToggleCommand { get; set; }
|
||||||
|
public Command ToolbarTappedCommand { get; set; }
|
||||||
|
|
||||||
|
public ViewModelIssue8741()
|
||||||
|
{
|
||||||
|
ChangeToggleCommand = new Command(ChangeToggle);
|
||||||
|
ToolbarTappedCommand = new Command(ToolbarTapped, () => Enabled);
|
||||||
|
EnabledText = Enabled ? "Enabled" : "Disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToolbarTapped()
|
||||||
|
{
|
||||||
|
ClickCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeToggle()
|
||||||
|
{
|
||||||
|
Enabled = !Enabled;
|
||||||
|
EnabledText = Enabled ? "Enabled" : "Disabled";
|
||||||
|
OnPropertyChanged(nameof(EnabledText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xamarin.Forms.CustomAttributes;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
|
||||||
|
#if UITEST
|
||||||
|
using Xamarin.Forms.Core.UITests;
|
||||||
|
using Xamarin.UITest;
|
||||||
|
using NUnit.Framework;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Controls.Issues
|
||||||
|
{
|
||||||
|
#if UITEST
|
||||||
|
[Category(UITestCategories.Image)]
|
||||||
|
#endif
|
||||||
|
[Preserve(AllMembers = true)]
|
||||||
|
[Issue(IssueTracker.Github, 8821, "Animations of downloaded gifs are not playing on Android", PlatformAffected.Android)]
|
||||||
|
public class Issue8821 : TestContentPage
|
||||||
|
{
|
||||||
|
Image _image;
|
||||||
|
|
||||||
|
public Issue8821()
|
||||||
|
{
|
||||||
|
var instructions = new Label
|
||||||
|
{
|
||||||
|
BackgroundColor = Color.Black,
|
||||||
|
TextColor = Color.White,
|
||||||
|
Text = "Press the DownloadFile button and then the Animate button. Verify that the gif is downloaded and animate without problems."
|
||||||
|
};
|
||||||
|
|
||||||
|
var downloadButton = new Button { Text = "DownloadFile" };
|
||||||
|
downloadButton.Clicked += async (sender, args) =>
|
||||||
|
{
|
||||||
|
string nextURL = "https://upload.wikimedia.org/wikipedia/commons/c/c0/An_example_animation_made_with_Pivot.gif";
|
||||||
|
|
||||||
|
await CreateImage(nextURL);
|
||||||
|
};
|
||||||
|
|
||||||
|
_image = new Image { Source = string.Empty };
|
||||||
|
|
||||||
|
var animateButton = new Button { Text = "Animate" };
|
||||||
|
animateButton.Clicked += (sender, args) =>
|
||||||
|
{
|
||||||
|
_image.IsAnimationPlaying = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Content = new StackLayout
|
||||||
|
{
|
||||||
|
Padding = new Thickness(20, 35, 20, 20),
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
instructions,
|
||||||
|
downloadButton,
|
||||||
|
_image,
|
||||||
|
animateButton
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SecondImageSource { get; set; }
|
||||||
|
|
||||||
|
protected override void Init()
|
||||||
|
{
|
||||||
|
Title = "Issue 8821";
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task CreateImage(string imageUrl)
|
||||||
|
{
|
||||||
|
var bytes = await DownloadImageAsync(imageUrl);
|
||||||
|
|
||||||
|
string path;
|
||||||
|
|
||||||
|
#if WINDOWS_UWP
|
||||||
|
path = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
|
||||||
|
#else
|
||||||
|
path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
|
||||||
|
#endif
|
||||||
|
SecondImageSource = Path.Combine(path, "Issue8821.gif");
|
||||||
|
File.WriteAllBytes(SecondImageSource, bytes);
|
||||||
|
|
||||||
|
_image.Source = SecondImageSource;
|
||||||
|
OnPropertyChanged(nameof(SecondImageSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task<byte[]> DownloadImageAsync(string imageUrl)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var httpClient = new HttpClient())
|
||||||
|
using (var httpResponse = await httpClient.GetAsync(imageUrl))
|
||||||
|
{
|
||||||
|
if (httpResponse.StatusCode == HttpStatusCode.OK)
|
||||||
|
return await httpResponse.Content.ReadAsByteArrayAsync();
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -693,6 +693,7 @@ namespace Xamarin.Forms.Controls
|
||||||
item.Title = shellItemTitle;
|
item.Title = shellItemTitle;
|
||||||
|
|
||||||
TShellSection shellSection = Activator.CreateInstance<TShellSection>();
|
TShellSection shellSection = Activator.CreateInstance<TShellSection>();
|
||||||
|
shellSection.Title = shellItemTitle;
|
||||||
|
|
||||||
shellSection.Items.Add(new ShellContent()
|
shellSection.Items.Add(new ShellContent()
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<DependentUpon>Issue3228.xaml</DependentUpon>
|
<DependentUpon>Issue3228.xaml</DependentUpon>
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8262.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8207.xaml.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8207.xaml.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue6362.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue6362.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7505.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue7505.cs" />
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterView.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewHeaderFooterView.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewItemsUpdatingScrollMode.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)CollectionViewItemsUpdatingScrollMode.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue4606.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue4606.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8644.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8177.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8177.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue4744.xaml.cs">
|
<Compile Include="$(MSBuildThisFileDirectory)Issue4744.xaml.cs">
|
||||||
<DependentUpon>Issue4744.xaml</DependentUpon>
|
<DependentUpon>Issue4744.xaml</DependentUpon>
|
||||||
|
@ -148,6 +150,7 @@
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7963.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue7963.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8741.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)RefreshViewTests.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)RefreshViewTests.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7338.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue7338.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)ScrollToGroup.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)ScrollToGroup.cs" />
|
||||||
|
@ -1213,9 +1216,11 @@
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8638.xaml.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8638.xaml.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8392.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8392.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8672.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8672.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8821.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8326.xaml.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8326.xaml.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue8449.xaml.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8449.xaml.cs" />
|
||||||
<Compile Include="$(MSBuildThisFileDirectory)Issue7875.cs" />
|
<Compile Include="$(MSBuildThisFileDirectory)Issue7875.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Issue8461.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
|
<EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
|
||||||
|
|
|
@ -329,5 +329,16 @@ namespace Xamarin.Forms.Core.UnitTests
|
||||||
{
|
{
|
||||||
Assert.AreEqual(Color.Default, (Color)System.Drawing.Color.Empty);
|
Assert.AreEqual(Color.Default, (Color)System.Drawing.Color.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void DefaultColorsMatch()
|
||||||
|
{
|
||||||
|
//This spot-checks a few of the fields in Color
|
||||||
|
Assert.AreEqual(Color.CornflowerBlue, Color.FromRgb(100, 149, 237));
|
||||||
|
Assert.AreEqual(Color.DarkSalmon, Color.FromRgb(233, 150, 122));
|
||||||
|
Assert.AreEqual(Color.Transparent, Color.FromRgba(255, 255, 255, 0));
|
||||||
|
Assert.AreEqual(Color.Wheat, Color.FromRgb(245, 222, 179));
|
||||||
|
Assert.AreEqual(Color.White, Color.FromRgb(255, 255, 255));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Core.UnitTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class NumericExtensionsTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void InRange()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(5, 5.Clamp(0, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void BelowMin()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(5, 0.Clamp(5, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AboveMax()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(5, 10.Clamp(0, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MinMaxWrong()
|
||||||
|
{
|
||||||
|
Assert.AreEqual(0, 10.Clamp(5, 0));
|
||||||
|
Assert.AreEqual(0, 5.Clamp(10, 0));
|
||||||
|
Assert.AreEqual(5, 0.Clamp(10, 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -76,6 +76,7 @@
|
||||||
<Compile Include="CommandSourceTests.cs" />
|
<Compile Include="CommandSourceTests.cs" />
|
||||||
<Compile Include="CommandTests.cs" />
|
<Compile Include="CommandTests.cs" />
|
||||||
<Compile Include="DependencyResolutionTests.cs" />
|
<Compile Include="DependencyResolutionTests.cs" />
|
||||||
|
<Compile Include="NumericExtensionsTests.cs" />
|
||||||
<Compile Include="RefreshViewTests.cs" />
|
<Compile Include="RefreshViewTests.cs" />
|
||||||
<Compile Include="MockDispatcherProvider.cs" />
|
<Compile Include="MockDispatcherProvider.cs" />
|
||||||
<Compile Include="MockDispatcher.cs" />
|
<Compile Include="MockDispatcher.cs" />
|
||||||
|
|
|
@ -279,15 +279,16 @@ namespace Xamarin.Forms
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//defined on a base class ?
|
||||||
|
if (sourceType.BaseType is Type baseT && GetIndexer(baseT.GetTypeInfo(), indexerName, content) is PropertyInfo p)
|
||||||
|
return p;
|
||||||
|
|
||||||
//defined on an interface ?
|
//defined on an interface ?
|
||||||
foreach (var face in sourceType.ImplementedInterfaces) {
|
foreach (var face in sourceType.ImplementedInterfaces) {
|
||||||
if (GetIndexer(face.GetTypeInfo(), indexerName, content) is PropertyInfo pi)
|
if (GetIndexer(face.GetTypeInfo(), indexerName, content) is PropertyInfo pi)
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
//defined on a base class ?
|
|
||||||
if (sourceType.BaseType is Type baseT && GetIndexer(baseT.GetTypeInfo(), indexerName, content) is PropertyInfo p)
|
|
||||||
return p;
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,26 @@ namespace Xamarin.Forms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color(int r, int g, int b)
|
||||||
|
{
|
||||||
|
_mode = Mode.Rgb;
|
||||||
|
_r = r / 255f;
|
||||||
|
_g = g / 255f;
|
||||||
|
_b = b / 255f;
|
||||||
|
_a = 1;
|
||||||
|
ConvertToHsl(_r, _g, _b, _mode, out _hue, out _saturation, out _luminosity);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color(int r, int g, int b, int a)
|
||||||
|
{
|
||||||
|
_mode = Mode.Rgb;
|
||||||
|
_r = r / 255f;
|
||||||
|
_g = g / 255f;
|
||||||
|
_b = b / 255f;
|
||||||
|
_a = a / 255f;
|
||||||
|
ConvertToHsl(_r, _g, _b, _mode, out _hue, out _saturation, out _luminosity);
|
||||||
|
}
|
||||||
|
|
||||||
public Color(double r, double g, double b) : this(r, g, b, 1)
|
public Color(double r, double g, double b) : this(r, g, b, 1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -418,150 +438,150 @@ namespace Xamarin.Forms
|
||||||
#region Color Definitions
|
#region Color Definitions
|
||||||
|
|
||||||
// matches colors in WPF's System.Windows.Media.Colors
|
// matches colors in WPF's System.Windows.Media.Colors
|
||||||
public static readonly Color AliceBlue = FromRgb(240, 248, 255);
|
public static readonly Color AliceBlue = new Color(240, 248, 255);
|
||||||
public static readonly Color AntiqueWhite = FromRgb(250, 235, 215);
|
public static readonly Color AntiqueWhite = new Color(250, 235, 215);
|
||||||
public static readonly Color Aqua = FromRgb(0, 255, 255);
|
public static readonly Color Aqua = new Color(0, 255, 255);
|
||||||
public static readonly Color Aquamarine = FromRgb(127, 255, 212);
|
public static readonly Color Aquamarine = new Color(127, 255, 212);
|
||||||
public static readonly Color Azure = FromRgb(240, 255, 255);
|
public static readonly Color Azure = new Color(240, 255, 255);
|
||||||
public static readonly Color Beige = FromRgb(245, 245, 220);
|
public static readonly Color Beige = new Color(245, 245, 220);
|
||||||
public static readonly Color Bisque = FromRgb(255, 228, 196);
|
public static readonly Color Bisque = new Color(255, 228, 196);
|
||||||
public static readonly Color Black = FromRgb(0, 0, 0);
|
public static readonly Color Black = new Color(0, 0, 0);
|
||||||
public static readonly Color BlanchedAlmond = FromRgb(255, 235, 205);
|
public static readonly Color BlanchedAlmond = new Color(255, 235, 205);
|
||||||
public static readonly Color Blue = FromRgb(0, 0, 255);
|
public static readonly Color Blue = new Color(0, 0, 255);
|
||||||
public static readonly Color BlueViolet = FromRgb(138, 43, 226);
|
public static readonly Color BlueViolet = new Color(138, 43, 226);
|
||||||
public static readonly Color Brown = FromRgb(165, 42, 42);
|
public static readonly Color Brown = new Color(165, 42, 42);
|
||||||
public static readonly Color BurlyWood = FromRgb(222, 184, 135);
|
public static readonly Color BurlyWood = new Color(222, 184, 135);
|
||||||
public static readonly Color CadetBlue = FromRgb(95, 158, 160);
|
public static readonly Color CadetBlue = new Color(95, 158, 160);
|
||||||
public static readonly Color Chartreuse = FromRgb(127, 255, 0);
|
public static readonly Color Chartreuse = new Color(127, 255, 0);
|
||||||
public static readonly Color Chocolate = FromRgb(210, 105, 30);
|
public static readonly Color Chocolate = new Color(210, 105, 30);
|
||||||
public static readonly Color Coral = FromRgb(255, 127, 80);
|
public static readonly Color Coral = new Color(255, 127, 80);
|
||||||
public static readonly Color CornflowerBlue = FromRgb(100, 149, 237);
|
public static readonly Color CornflowerBlue = new Color(100, 149, 237);
|
||||||
public static readonly Color Cornsilk = FromRgb(255, 248, 220);
|
public static readonly Color Cornsilk = new Color(255, 248, 220);
|
||||||
public static readonly Color Crimson = FromRgb(220, 20, 60);
|
public static readonly Color Crimson = new Color(220, 20, 60);
|
||||||
public static readonly Color Cyan = FromRgb(0, 255, 255);
|
public static readonly Color Cyan = new Color(0, 255, 255);
|
||||||
public static readonly Color DarkBlue = FromRgb(0, 0, 139);
|
public static readonly Color DarkBlue = new Color(0, 0, 139);
|
||||||
public static readonly Color DarkCyan = FromRgb(0, 139, 139);
|
public static readonly Color DarkCyan = new Color(0, 139, 139);
|
||||||
public static readonly Color DarkGoldenrod = FromRgb(184, 134, 11);
|
public static readonly Color DarkGoldenrod = new Color(184, 134, 11);
|
||||||
public static readonly Color DarkGray = FromRgb(169, 169, 169);
|
public static readonly Color DarkGray = new Color(169, 169, 169);
|
||||||
public static readonly Color DarkGreen = FromRgb(0, 100, 0);
|
public static readonly Color DarkGreen = new Color(0, 100, 0);
|
||||||
public static readonly Color DarkKhaki = FromRgb(189, 183, 107);
|
public static readonly Color DarkKhaki = new Color(189, 183, 107);
|
||||||
public static readonly Color DarkMagenta = FromRgb(139, 0, 139);
|
public static readonly Color DarkMagenta = new Color(139, 0, 139);
|
||||||
public static readonly Color DarkOliveGreen = FromRgb(85, 107, 47);
|
public static readonly Color DarkOliveGreen = new Color(85, 107, 47);
|
||||||
public static readonly Color DarkOrange = FromRgb(255, 140, 0);
|
public static readonly Color DarkOrange = new Color(255, 140, 0);
|
||||||
public static readonly Color DarkOrchid = FromRgb(153, 50, 204);
|
public static readonly Color DarkOrchid = new Color(153, 50, 204);
|
||||||
public static readonly Color DarkRed = FromRgb(139, 0, 0);
|
public static readonly Color DarkRed = new Color(139, 0, 0);
|
||||||
public static readonly Color DarkSalmon = FromRgb(233, 150, 122);
|
public static readonly Color DarkSalmon = new Color(233, 150, 122);
|
||||||
public static readonly Color DarkSeaGreen = FromRgb(143, 188, 143);
|
public static readonly Color DarkSeaGreen = new Color(143, 188, 143);
|
||||||
public static readonly Color DarkSlateBlue = FromRgb(72, 61, 139);
|
public static readonly Color DarkSlateBlue = new Color(72, 61, 139);
|
||||||
public static readonly Color DarkSlateGray = FromRgb(47, 79, 79);
|
public static readonly Color DarkSlateGray = new Color(47, 79, 79);
|
||||||
public static readonly Color DarkTurquoise = FromRgb(0, 206, 209);
|
public static readonly Color DarkTurquoise = new Color(0, 206, 209);
|
||||||
public static readonly Color DarkViolet = FromRgb(148, 0, 211);
|
public static readonly Color DarkViolet = new Color(148, 0, 211);
|
||||||
public static readonly Color DeepPink = FromRgb(255, 20, 147);
|
public static readonly Color DeepPink = new Color(255, 20, 147);
|
||||||
public static readonly Color DeepSkyBlue = FromRgb(0, 191, 255);
|
public static readonly Color DeepSkyBlue = new Color(0, 191, 255);
|
||||||
public static readonly Color DimGray = FromRgb(105, 105, 105);
|
public static readonly Color DimGray = new Color(105, 105, 105);
|
||||||
public static readonly Color DodgerBlue = FromRgb(30, 144, 255);
|
public static readonly Color DodgerBlue = new Color(30, 144, 255);
|
||||||
public static readonly Color Firebrick = FromRgb(178, 34, 34);
|
public static readonly Color Firebrick = new Color(178, 34, 34);
|
||||||
public static readonly Color FloralWhite = FromRgb(255, 250, 240);
|
public static readonly Color FloralWhite = new Color(255, 250, 240);
|
||||||
public static readonly Color ForestGreen = FromRgb(34, 139, 34);
|
public static readonly Color ForestGreen = new Color(34, 139, 34);
|
||||||
public static readonly Color Fuchsia = FromRgb(255, 0, 255);
|
public static readonly Color Fuchsia = new Color(255, 0, 255);
|
||||||
[Obsolete("Fuschia is obsolete as of version 1.3.0. Please use Fuchsia instead.")]
|
[Obsolete("Fuschia is obsolete as of version 1.3.0. Please use Fuchsia instead.")]
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public static readonly Color Fuschia = FromRgb(255, 0, 255);
|
public static readonly Color Fuschia = new Color(255, 0, 255);
|
||||||
public static readonly Color Gainsboro = FromRgb(220, 220, 220);
|
public static readonly Color Gainsboro = new Color(220, 220, 220);
|
||||||
public static readonly Color GhostWhite = FromRgb(248, 248, 255);
|
public static readonly Color GhostWhite = new Color(248, 248, 255);
|
||||||
public static readonly Color Gold = FromRgb(255, 215, 0);
|
public static readonly Color Gold = new Color(255, 215, 0);
|
||||||
public static readonly Color Goldenrod = FromRgb(218, 165, 32);
|
public static readonly Color Goldenrod = new Color(218, 165, 32);
|
||||||
public static readonly Color Gray = FromRgb(128, 128, 128);
|
public static readonly Color Gray = new Color(128, 128, 128);
|
||||||
public static readonly Color Green = FromRgb(0, 128, 0);
|
public static readonly Color Green = new Color(0, 128, 0);
|
||||||
public static readonly Color GreenYellow = FromRgb(173, 255, 47);
|
public static readonly Color GreenYellow = new Color(173, 255, 47);
|
||||||
public static readonly Color Honeydew = FromRgb(240, 255, 240);
|
public static readonly Color Honeydew = new Color(240, 255, 240);
|
||||||
public static readonly Color HotPink = FromRgb(255, 105, 180);
|
public static readonly Color HotPink = new Color(255, 105, 180);
|
||||||
public static readonly Color IndianRed = FromRgb(205, 92, 92);
|
public static readonly Color IndianRed = new Color(205, 92, 92);
|
||||||
public static readonly Color Indigo = FromRgb(75, 0, 130);
|
public static readonly Color Indigo = new Color(75, 0, 130);
|
||||||
public static readonly Color Ivory = FromRgb(255, 255, 240);
|
public static readonly Color Ivory = new Color(255, 255, 240);
|
||||||
public static readonly Color Khaki = FromRgb(240, 230, 140);
|
public static readonly Color Khaki = new Color(240, 230, 140);
|
||||||
public static readonly Color Lavender = FromRgb(230, 230, 250);
|
public static readonly Color Lavender = new Color(230, 230, 250);
|
||||||
public static readonly Color LavenderBlush = FromRgb(255, 240, 245);
|
public static readonly Color LavenderBlush = new Color(255, 240, 245);
|
||||||
public static readonly Color LawnGreen = FromRgb(124, 252, 0);
|
public static readonly Color LawnGreen = new Color(124, 252, 0);
|
||||||
public static readonly Color LemonChiffon = FromRgb(255, 250, 205);
|
public static readonly Color LemonChiffon = new Color(255, 250, 205);
|
||||||
public static readonly Color LightBlue = FromRgb(173, 216, 230);
|
public static readonly Color LightBlue = new Color(173, 216, 230);
|
||||||
public static readonly Color LightCoral = FromRgb(240, 128, 128);
|
public static readonly Color LightCoral = new Color(240, 128, 128);
|
||||||
public static readonly Color LightCyan = FromRgb(224, 255, 255);
|
public static readonly Color LightCyan = new Color(224, 255, 255);
|
||||||
public static readonly Color LightGoldenrodYellow = FromRgb(250, 250, 210);
|
public static readonly Color LightGoldenrodYellow = new Color(250, 250, 210);
|
||||||
public static readonly Color LightGray = FromRgb(211, 211, 211);
|
public static readonly Color LightGray = new Color(211, 211, 211);
|
||||||
public static readonly Color LightGreen = FromRgb(144, 238, 144);
|
public static readonly Color LightGreen = new Color(144, 238, 144);
|
||||||
public static readonly Color LightPink = FromRgb(255, 182, 193);
|
public static readonly Color LightPink = new Color(255, 182, 193);
|
||||||
public static readonly Color LightSalmon = FromRgb(255, 160, 122);
|
public static readonly Color LightSalmon = new Color(255, 160, 122);
|
||||||
public static readonly Color LightSeaGreen = FromRgb(32, 178, 170);
|
public static readonly Color LightSeaGreen = new Color(32, 178, 170);
|
||||||
public static readonly Color LightSkyBlue = FromRgb(135, 206, 250);
|
public static readonly Color LightSkyBlue = new Color(135, 206, 250);
|
||||||
public static readonly Color LightSlateGray = FromRgb(119, 136, 153);
|
public static readonly Color LightSlateGray = new Color(119, 136, 153);
|
||||||
public static readonly Color LightSteelBlue = FromRgb(176, 196, 222);
|
public static readonly Color LightSteelBlue = new Color(176, 196, 222);
|
||||||
public static readonly Color LightYellow = FromRgb(255, 255, 224);
|
public static readonly Color LightYellow = new Color(255, 255, 224);
|
||||||
public static readonly Color Lime = FromRgb(0, 255, 0);
|
public static readonly Color Lime = new Color(0, 255, 0);
|
||||||
public static readonly Color LimeGreen = FromRgb(50, 205, 50);
|
public static readonly Color LimeGreen = new Color(50, 205, 50);
|
||||||
public static readonly Color Linen = FromRgb(250, 240, 230);
|
public static readonly Color Linen = new Color(250, 240, 230);
|
||||||
public static readonly Color Magenta = FromRgb(255, 0, 255);
|
public static readonly Color Magenta = new Color(255, 0, 255);
|
||||||
public static readonly Color Maroon = FromRgb(128, 0, 0);
|
public static readonly Color Maroon = new Color(128, 0, 0);
|
||||||
public static readonly Color MediumAquamarine = FromRgb(102, 205, 170);
|
public static readonly Color MediumAquamarine = new Color(102, 205, 170);
|
||||||
public static readonly Color MediumBlue = FromRgb(0, 0, 205);
|
public static readonly Color MediumBlue = new Color(0, 0, 205);
|
||||||
public static readonly Color MediumOrchid = FromRgb(186, 85, 211);
|
public static readonly Color MediumOrchid = new Color(186, 85, 211);
|
||||||
public static readonly Color MediumPurple = FromRgb(147, 112, 219);
|
public static readonly Color MediumPurple = new Color(147, 112, 219);
|
||||||
public static readonly Color MediumSeaGreen = FromRgb(60, 179, 113);
|
public static readonly Color MediumSeaGreen = new Color(60, 179, 113);
|
||||||
public static readonly Color MediumSlateBlue = FromRgb(123, 104, 238);
|
public static readonly Color MediumSlateBlue = new Color(123, 104, 238);
|
||||||
public static readonly Color MediumSpringGreen = FromRgb(0, 250, 154);
|
public static readonly Color MediumSpringGreen = new Color(0, 250, 154);
|
||||||
public static readonly Color MediumTurquoise = FromRgb(72, 209, 204);
|
public static readonly Color MediumTurquoise = new Color(72, 209, 204);
|
||||||
public static readonly Color MediumVioletRed = FromRgb(199, 21, 133);
|
public static readonly Color MediumVioletRed = new Color(199, 21, 133);
|
||||||
public static readonly Color MidnightBlue = FromRgb(25, 25, 112);
|
public static readonly Color MidnightBlue = new Color(25, 25, 112);
|
||||||
public static readonly Color MintCream = FromRgb(245, 255, 250);
|
public static readonly Color MintCream = new Color(245, 255, 250);
|
||||||
public static readonly Color MistyRose = FromRgb(255, 228, 225);
|
public static readonly Color MistyRose = new Color(255, 228, 225);
|
||||||
public static readonly Color Moccasin = FromRgb(255, 228, 181);
|
public static readonly Color Moccasin = new Color(255, 228, 181);
|
||||||
public static readonly Color NavajoWhite = FromRgb(255, 222, 173);
|
public static readonly Color NavajoWhite = new Color(255, 222, 173);
|
||||||
public static readonly Color Navy = FromRgb(0, 0, 128);
|
public static readonly Color Navy = new Color(0, 0, 128);
|
||||||
public static readonly Color OldLace = FromRgb(253, 245, 230);
|
public static readonly Color OldLace = new Color(253, 245, 230);
|
||||||
public static readonly Color Olive = FromRgb(128, 128, 0);
|
public static readonly Color Olive = new Color(128, 128, 0);
|
||||||
public static readonly Color OliveDrab = FromRgb(107, 142, 35);
|
public static readonly Color OliveDrab = new Color(107, 142, 35);
|
||||||
public static readonly Color Orange = FromRgb(255, 165, 0);
|
public static readonly Color Orange = new Color(255, 165, 0);
|
||||||
public static readonly Color OrangeRed = FromRgb(255, 69, 0);
|
public static readonly Color OrangeRed = new Color(255, 69, 0);
|
||||||
public static readonly Color Orchid = FromRgb(218, 112, 214);
|
public static readonly Color Orchid = new Color(218, 112, 214);
|
||||||
public static readonly Color PaleGoldenrod = FromRgb(238, 232, 170);
|
public static readonly Color PaleGoldenrod = new Color(238, 232, 170);
|
||||||
public static readonly Color PaleGreen = FromRgb(152, 251, 152);
|
public static readonly Color PaleGreen = new Color(152, 251, 152);
|
||||||
public static readonly Color PaleTurquoise = FromRgb(175, 238, 238);
|
public static readonly Color PaleTurquoise = new Color(175, 238, 238);
|
||||||
public static readonly Color PaleVioletRed = FromRgb(219, 112, 147);
|
public static readonly Color PaleVioletRed = new Color(219, 112, 147);
|
||||||
public static readonly Color PapayaWhip = FromRgb(255, 239, 213);
|
public static readonly Color PapayaWhip = new Color(255, 239, 213);
|
||||||
public static readonly Color PeachPuff = FromRgb(255, 218, 185);
|
public static readonly Color PeachPuff = new Color(255, 218, 185);
|
||||||
public static readonly Color Peru = FromRgb(205, 133, 63);
|
public static readonly Color Peru = new Color(205, 133, 63);
|
||||||
public static readonly Color Pink = FromRgb(255, 192, 203);
|
public static readonly Color Pink = new Color(255, 192, 203);
|
||||||
public static readonly Color Plum = FromRgb(221, 160, 221);
|
public static readonly Color Plum = new Color(221, 160, 221);
|
||||||
public static readonly Color PowderBlue = FromRgb(176, 224, 230);
|
public static readonly Color PowderBlue = new Color(176, 224, 230);
|
||||||
public static readonly Color Purple = FromRgb(128, 0, 128);
|
public static readonly Color Purple = new Color(128, 0, 128);
|
||||||
public static readonly Color Red = FromRgb(255, 0, 0);
|
public static readonly Color Red = new Color(255, 0, 0);
|
||||||
public static readonly Color RosyBrown = FromRgb(188, 143, 143);
|
public static readonly Color RosyBrown = new Color(188, 143, 143);
|
||||||
public static readonly Color RoyalBlue = FromRgb(65, 105, 225);
|
public static readonly Color RoyalBlue = new Color(65, 105, 225);
|
||||||
public static readonly Color SaddleBrown = FromRgb(139, 69, 19);
|
public static readonly Color SaddleBrown = new Color(139, 69, 19);
|
||||||
public static readonly Color Salmon = FromRgb(250, 128, 114);
|
public static readonly Color Salmon = new Color(250, 128, 114);
|
||||||
public static readonly Color SandyBrown = FromRgb(244, 164, 96);
|
public static readonly Color SandyBrown = new Color(244, 164, 96);
|
||||||
public static readonly Color SeaGreen = FromRgb(46, 139, 87);
|
public static readonly Color SeaGreen = new Color(46, 139, 87);
|
||||||
public static readonly Color SeaShell = FromRgb(255, 245, 238);
|
public static readonly Color SeaShell = new Color(255, 245, 238);
|
||||||
public static readonly Color Sienna = FromRgb(160, 82, 45);
|
public static readonly Color Sienna = new Color(160, 82, 45);
|
||||||
public static readonly Color Silver = FromRgb(192, 192, 192);
|
public static readonly Color Silver = new Color(192, 192, 192);
|
||||||
public static readonly Color SkyBlue = FromRgb(135, 206, 235);
|
public static readonly Color SkyBlue = new Color(135, 206, 235);
|
||||||
public static readonly Color SlateBlue = FromRgb(106, 90, 205);
|
public static readonly Color SlateBlue = new Color(106, 90, 205);
|
||||||
public static readonly Color SlateGray = FromRgb(112, 128, 144);
|
public static readonly Color SlateGray = new Color(112, 128, 144);
|
||||||
public static readonly Color Snow = FromRgb(255, 250, 250);
|
public static readonly Color Snow = new Color(255, 250, 250);
|
||||||
public static readonly Color SpringGreen = FromRgb(0, 255, 127);
|
public static readonly Color SpringGreen = new Color(0, 255, 127);
|
||||||
public static readonly Color SteelBlue = FromRgb(70, 130, 180);
|
public static readonly Color SteelBlue = new Color(70, 130, 180);
|
||||||
public static readonly Color Tan = FromRgb(210, 180, 140);
|
public static readonly Color Tan = new Color(210, 180, 140);
|
||||||
public static readonly Color Teal = FromRgb(0, 128, 128);
|
public static readonly Color Teal = new Color(0, 128, 128);
|
||||||
public static readonly Color Thistle = FromRgb(216, 191, 216);
|
public static readonly Color Thistle = new Color(216, 191, 216);
|
||||||
public static readonly Color Tomato = FromRgb(255, 99, 71);
|
public static readonly Color Tomato = new Color(255, 99, 71);
|
||||||
public static readonly Color Transparent = FromRgba(255, 255, 255, 0);
|
public static readonly Color Transparent = new Color(255, 255, 255, 0);
|
||||||
public static readonly Color Turquoise = FromRgb(64, 224, 208);
|
public static readonly Color Turquoise = new Color(64, 224, 208);
|
||||||
public static readonly Color Violet = FromRgb(238, 130, 238);
|
public static readonly Color Violet = new Color(238, 130, 238);
|
||||||
public static readonly Color Wheat = FromRgb(245, 222, 179);
|
public static readonly Color Wheat = new Color(245, 222, 179);
|
||||||
public static readonly Color White = FromRgb(255, 255, 255);
|
public static readonly Color White = new Color(255, 255, 255);
|
||||||
public static readonly Color WhiteSmoke = FromRgb(245, 245, 245);
|
public static readonly Color WhiteSmoke = new Color(245, 245, 245);
|
||||||
public static readonly Color Yellow = FromRgb(255, 255, 0);
|
public static readonly Color Yellow = new Color(255, 255, 0);
|
||||||
public static readonly Color YellowGreen = FromRgb(154, 205, 50);
|
public static readonly Color YellowGreen = new Color(154, 205, 50);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,33 +109,15 @@ namespace Xamarin.Forms
|
||||||
if (s_initialized)
|
if (s_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Type targetAttrType = typeof(DependencyAttribute);
|
|
||||||
|
|
||||||
// Don't use LINQ for performance reasons
|
// Don't use LINQ for performance reasons
|
||||||
// Naive implementation can easily take over a second to run
|
// Naive implementation can easily take over a second to run
|
||||||
foreach (Assembly assembly in assemblies)
|
foreach (Assembly assembly in assemblies)
|
||||||
{
|
{
|
||||||
object[] attributes;
|
object[] attributes = assembly.GetCustomAttributesSafe(typeof(DependencyAttribute));
|
||||||
try
|
if (attributes == null)
|
||||||
{
|
|
||||||
#if NETSTANDARD2_0
|
|
||||||
attributes = assembly.GetCustomAttributes(targetAttrType, true);
|
|
||||||
#else
|
|
||||||
attributes = assembly.GetCustomAttributes(targetAttrType).ToArray();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
catch (System.IO.FileNotFoundException)
|
|
||||||
{
|
|
||||||
// Sometimes the previewer doesn't actually have everything required for these loads to work
|
|
||||||
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, targetAttrType.FullName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var length = attributes.Length;
|
|
||||||
if (length == 0)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < attributes.Length; i++)
|
||||||
{
|
{
|
||||||
DependencyAttribute attribute = (DependencyAttribute)attributes[i];
|
DependencyAttribute attribute = (DependencyAttribute)attributes[i];
|
||||||
if (!DependencyTypes.Contains(attribute.Implementor))
|
if (!DependencyTypes.Contains(attribute.Implementor))
|
||||||
|
|
|
@ -12,6 +12,11 @@ namespace Xamarin.Forms.Internals
|
||||||
{
|
{
|
||||||
int _masterDetails;
|
int _masterDetails;
|
||||||
Page _target;
|
Page _target;
|
||||||
|
ToolBarItemComparer _toolBarItemComparer;
|
||||||
|
public ToolbarTracker()
|
||||||
|
{
|
||||||
|
_toolBarItemComparer = new ToolBarItemComparer();
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerable<Page> AdditionalTargets { get; set; }
|
public IEnumerable<Page> AdditionalTargets { get; set; }
|
||||||
|
|
||||||
|
@ -44,12 +49,20 @@ namespace Xamarin.Forms.Internals
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Target == null)
|
if (Target == null)
|
||||||
return Enumerable.Empty<ToolbarItem>();
|
return new ToolbarItem[0];
|
||||||
IEnumerable<ToolbarItem> items = GetCurrentToolbarItems(Target);
|
|
||||||
if (AdditionalTargets != null)
|
|
||||||
items = items.Concat(AdditionalTargets.SelectMany(t => t.ToolbarItems));
|
|
||||||
|
|
||||||
return items.OrderBy(ti => ti.Priority);
|
// I realize this is sorting on every single get but we don't have
|
||||||
|
// a mechanism in place currently to invalidate a stored version of this
|
||||||
|
|
||||||
|
List<ToolbarItem> returnValue = GetCurrentToolbarItems(Target);
|
||||||
|
|
||||||
|
if (AdditionalTargets != null)
|
||||||
|
foreach(var item in AdditionalTargets)
|
||||||
|
foreach(var toolbarItem in item.ToolbarItems)
|
||||||
|
returnValue.Add(toolbarItem);
|
||||||
|
|
||||||
|
returnValue.Sort(_toolBarItemComparer);
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +71,7 @@ namespace Xamarin.Forms.Internals
|
||||||
void EmitCollectionChanged()
|
void EmitCollectionChanged()
|
||||||
=> CollectionChanged?.Invoke(this, EventArgs.Empty);
|
=> CollectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
IEnumerable<ToolbarItem> GetCurrentToolbarItems(Page page)
|
List<ToolbarItem> GetCurrentToolbarItems(Page page)
|
||||||
{
|
{
|
||||||
var result = new List<ToolbarItem>();
|
var result = new List<ToolbarItem>();
|
||||||
result.AddRange(page.ToolbarItems);
|
result.AddRange(page.ToolbarItems);
|
||||||
|
@ -178,5 +191,10 @@ namespace Xamarin.Forms.Internals
|
||||||
page.DescendantRemoved -= OnChildRemoved;
|
page.DescendantRemoved -= OnChildRemoved;
|
||||||
page.PropertyChanged -= OnPropertyChanged;
|
page.PropertyChanged -= OnPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ToolBarItemComparer : IComparer<ToolbarItem>
|
||||||
|
{
|
||||||
|
public int Compare(ToolbarItem x, ToolbarItem y) => x.Priority.CompareTo(y.Priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,20 +1,48 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Xamarin.Forms.Internals
|
namespace Xamarin.Forms.Internals
|
||||||
{
|
{
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public static class NumericExtensions
|
public static class NumericExtensions
|
||||||
{
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static double Clamp(this double self, double min, double max)
|
public static double Clamp(this double self, double min, double max)
|
||||||
{
|
{
|
||||||
return Math.Min(max, Math.Max(self, min));
|
if (max < min)
|
||||||
|
{
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
else if (self < min)
|
||||||
|
{
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
else if (self > max)
|
||||||
|
{
|
||||||
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Clamp(this int self, int min, int max)
|
public static int Clamp(this int self, int min, int max)
|
||||||
{
|
{
|
||||||
return Math.Min(max, Math.Max(self, min));
|
if (max < min)
|
||||||
|
{
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
else if (self < min)
|
||||||
|
{
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
else if (self > max)
|
||||||
|
{
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,8 @@ namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
|
||||||
{
|
{
|
||||||
public static readonly BindableProperty BlendColorProperty = BindableProperty.Create("BlendColor", typeof(Color), typeof(FormsElement), Color.Default);
|
public static readonly BindableProperty BlendColorProperty = BindableProperty.Create("BlendColor", typeof(Color), typeof(FormsElement), Color.Default);
|
||||||
|
|
||||||
|
public static readonly BindableProperty FileProperty = BindableProperty.Create("File", typeof(string), typeof(FormsElement), default(string));
|
||||||
|
|
||||||
public static Color GetBlendColor(BindableObject element)
|
public static Color GetBlendColor(BindableObject element)
|
||||||
{
|
{
|
||||||
return (Color)element.GetValue(BlendColorProperty);
|
return (Color)element.GetValue(BlendColorProperty);
|
||||||
|
@ -26,5 +28,26 @@ namespace Xamarin.Forms.PlatformConfiguration.TizenSpecific
|
||||||
SetBlendColor(config.Element, color);
|
SetBlendColor(config.Element, color);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetFile(BindableObject element)
|
||||||
|
{
|
||||||
|
return (string)element.GetValue(FileProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetFile(BindableObject element, string file)
|
||||||
|
{
|
||||||
|
element.SetValue(FileProperty, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetFile(this IPlatformElementConfiguration<Tizen, FormsElement> config)
|
||||||
|
{
|
||||||
|
return GetFile(config.Element);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPlatformElementConfiguration<Tizen, FormsElement> SetFile(this IPlatformElementConfiguration<Tizen, FormsElement> config, string file)
|
||||||
|
{
|
||||||
|
SetFile(config.Element, file);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,13 +47,12 @@ namespace Xamarin.Forms.Internals
|
||||||
|
|
||||||
internal static object[] GetCustomAttributesSafe(this Assembly assembly, Type attrType)
|
internal static object[] GetCustomAttributesSafe(this Assembly assembly, Type attrType)
|
||||||
{
|
{
|
||||||
object[] attributes = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if NETSTANDARD2_0
|
#if NETSTANDARD2_0
|
||||||
attributes = assembly.GetCustomAttributes(attrType, true);
|
return assembly.GetCustomAttributes(attrType, true);
|
||||||
#else
|
#else
|
||||||
attributes = assembly.GetCustomAttributes(attrType).ToArray();
|
return assembly.GetCustomAttributes(attrType).ToArray();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
catch (System.IO.FileNotFoundException)
|
catch (System.IO.FileNotFoundException)
|
||||||
|
@ -62,7 +61,7 @@ namespace Xamarin.Forms.Internals
|
||||||
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attribute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
|
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attribute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return attributes;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type[] GetExportedTypes(this Assembly assembly)
|
public static Type[] GetExportedTypes(this Assembly assembly)
|
||||||
|
|
|
@ -336,19 +336,8 @@ namespace Xamarin.Forms.Internals
|
||||||
|
|
||||||
foreach (Type attrType in attrTypes)
|
foreach (Type attrType in attrTypes)
|
||||||
{
|
{
|
||||||
object[] attributes;
|
object[] attributes = assembly.GetCustomAttributesSafe(attrType);
|
||||||
try
|
if (attributes == null || attributes.Length == 0)
|
||||||
{
|
|
||||||
#if NETSTANDARD2_0
|
|
||||||
attributes = assembly.GetCustomAttributes(attrType, true);
|
|
||||||
#else
|
|
||||||
attributes = assembly.GetCustomAttributes(attrType).ToArray();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
catch (System.IO.FileNotFoundException)
|
|
||||||
{
|
|
||||||
// Sometimes the previewer doesn't actually have everything required for these loads to work
|
|
||||||
Log.Warning(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,19 +358,14 @@ namespace Xamarin.Forms.Internals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object[] effectAttributes = assembly.GetCustomAttributesSafe(typeof (ExportEffectAttribute));
|
||||||
|
if (effectAttributes == null || effectAttributes.Length == 0)
|
||||||
|
continue;
|
||||||
string resolutionName = assembly.FullName;
|
string resolutionName = assembly.FullName;
|
||||||
var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
|
var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
|
||||||
if (resolutionNameAttribute != null)
|
if (resolutionNameAttribute != null)
|
||||||
resolutionName = resolutionNameAttribute.ShortName;
|
resolutionName = resolutionNameAttribute.ShortName;
|
||||||
|
RegisterEffects(resolutionName, (ExportEffectAttribute[])effectAttributes);
|
||||||
#if NETSTANDARD2_0
|
|
||||||
object[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute), true);
|
|
||||||
#else
|
|
||||||
object[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute)).ToArray();
|
|
||||||
#endif
|
|
||||||
var typedEffectAttributes = new ExportEffectAttribute[effectAttributes.Length];
|
|
||||||
Array.Copy(effectAttributes, typedEffectAttributes, effectAttributes.Length);
|
|
||||||
RegisterEffects(resolutionName, typedEffectAttributes);
|
|
||||||
|
|
||||||
Profile.FrameEnd(assemblyName);
|
Profile.FrameEnd(assemblyName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,6 +220,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
||||||
}
|
}
|
||||||
|
|
||||||
AppCompatButton IButtonLayoutRenderer.View => Control;
|
AppCompatButton IButtonLayoutRenderer.View => Control;
|
||||||
bool IDisposedState.IsDisposed => _isDisposed;
|
bool IDisposedState.IsDisposed => _isDisposed || !Control.IsAlive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
CompoundButton.IOnCheckedChangeListener
|
CompoundButton.IOnCheckedChangeListener
|
||||||
{
|
{
|
||||||
bool _disposed;
|
bool _disposed;
|
||||||
bool _skipInvalidate;
|
|
||||||
int? _defaultLabelFor;
|
int? _defaultLabelFor;
|
||||||
VisualElementTracker _tracker;
|
VisualElementTracker _tracker;
|
||||||
VisualElementRenderer _visualElementRenderer;
|
VisualElementRenderer _visualElementRenderer;
|
||||||
|
@ -87,17 +86,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Invalidate()
|
|
||||||
{
|
|
||||||
if (_skipInvalidate)
|
|
||||||
{
|
|
||||||
_skipInvalidate = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
Size MinimumSize()
|
Size MinimumSize()
|
||||||
{
|
{
|
||||||
return new Size();
|
return new Size();
|
||||||
|
|
|
@ -23,7 +23,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
ITabStop
|
ITabStop
|
||||||
{
|
{
|
||||||
bool _disposed;
|
bool _disposed;
|
||||||
bool _skipInvalidate;
|
|
||||||
int? _defaultLabelFor;
|
int? _defaultLabelFor;
|
||||||
VisualElementTracker _tracker;
|
VisualElementTracker _tracker;
|
||||||
VisualElementRenderer _visualElementRenderer;
|
VisualElementRenderer _visualElementRenderer;
|
||||||
|
@ -85,17 +84,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Invalidate()
|
|
||||||
{
|
|
||||||
if (_skipInvalidate)
|
|
||||||
{
|
|
||||||
_skipInvalidate = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
Size MinimumSize()
|
Size MinimumSize()
|
||||||
{
|
{
|
||||||
return Size.Zero;
|
return Size.Zero;
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
AView IVisualElementRenderer.View => this;
|
AView IVisualElementRenderer.View => this;
|
||||||
ViewGroup IVisualElementRenderer.ViewGroup => null;
|
ViewGroup IVisualElementRenderer.ViewGroup => null;
|
||||||
VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
|
VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
|
||||||
bool IDisposedState.IsDisposed => _disposed;
|
bool IDisposedState.IsDisposed => ((IImageRendererController)this).IsDisposed;
|
||||||
|
|
||||||
public ImageButton Element
|
public ImageButton Element
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,7 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
}
|
}
|
||||||
|
|
||||||
void IImageRendererController.SkipInvalidate() => _skipInvalidate = true;
|
void IImageRendererController.SkipInvalidate() => _skipInvalidate = true;
|
||||||
bool IImageRendererController.IsDisposed => _disposed;
|
bool IImageRendererController.IsDisposed => _disposed || !Control.IsAlive();
|
||||||
|
|
||||||
AppCompatImageButton Control => this;
|
AppCompatImageButton Control => this;
|
||||||
public ImageButtonRenderer(Context context) : base(context)
|
public ImageButtonRenderer(Context context) : base(context)
|
||||||
|
|
|
@ -32,8 +32,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
||||||
{
|
{
|
||||||
public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>, IManageFragments, IOnClickListener, ILifeCycleState
|
public class NavigationPageRenderer : VisualElementRenderer<NavigationPage>, IManageFragments, IOnClickListener, ILifeCycleState
|
||||||
{
|
{
|
||||||
const int DefaultDisabledToolbarAlpha = 127;
|
|
||||||
|
|
||||||
readonly List<Fragment> _fragmentStack = new List<Fragment>();
|
readonly List<Fragment> _fragmentStack = new List<Fragment>();
|
||||||
|
|
||||||
Drawable _backgroundDrawable;
|
Drawable _backgroundDrawable;
|
||||||
|
@ -220,8 +218,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
||||||
{
|
{
|
||||||
_toolbarTracker.CollectionChanged -= ToolbarTrackerOnCollectionChanged;
|
_toolbarTracker.CollectionChanged -= ToolbarTrackerOnCollectionChanged;
|
||||||
|
|
||||||
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
|
_toolbar.DisposeMenuItems(_toolbarTracker?.ToolbarItems, OnToolbarItemPropertyChanged);
|
||||||
item.PropertyChanged -= OnToolbarItemPropertyChanged;
|
|
||||||
|
|
||||||
_toolbarTracker.Target = null;
|
_toolbarTracker.Target = null;
|
||||||
_toolbarTracker = null;
|
_toolbarTracker = null;
|
||||||
|
@ -562,8 +559,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
||||||
|
|
||||||
protected virtual void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
|
protected virtual void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName || e.PropertyName == MenuItem.TextProperty.PropertyName || e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
|
_toolbar.OnToolbarItemPropertyChanged(e, _toolbarTracker?.ToolbarItems, Context, null, OnToolbarItemPropertyChanged);
|
||||||
UpdateMenu();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertPageBefore(Page page, Page before)
|
void InsertPageBefore(Page page, Page before)
|
||||||
|
@ -909,51 +905,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AToolbar bar = _toolbar;
|
_toolbar.UpdateMenuItems(_toolbarTracker?.ToolbarItems, Context, null, OnToolbarItemPropertyChanged);
|
||||||
Context context = Context;
|
|
||||||
IMenu menu = bar.Menu;
|
|
||||||
|
|
||||||
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
|
|
||||||
item.PropertyChanged -= OnToolbarItemPropertyChanged;
|
|
||||||
menu.Clear();
|
|
||||||
|
|
||||||
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
|
|
||||||
{
|
|
||||||
IMenuItemController controller = item;
|
|
||||||
item.PropertyChanged += OnToolbarItemPropertyChanged;
|
|
||||||
if (item.Order == ToolbarItemOrder.Secondary)
|
|
||||||
{
|
|
||||||
IMenuItem menuItem = menu.Add(item.Text);
|
|
||||||
menuItem.SetEnabled(controller.IsEnabled);
|
|
||||||
menuItem.SetOnMenuItemClickListener(new GenericMenuClickListener(controller.Activate));
|
|
||||||
menuItem.SetTitleOrContentDescription(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IMenuItem menuItem = menu.Add(item.Text);
|
|
||||||
menuItem.SetEnabled(controller.IsEnabled);
|
|
||||||
UpdateMenuItemIcon(context, menuItem, item);
|
|
||||||
menuItem.SetShowAsAction(ShowAsAction.Always);
|
|
||||||
menuItem.SetOnMenuItemClickListener(new GenericMenuClickListener(controller.Activate));
|
|
||||||
menuItem.SetTitleOrContentDescription(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem)
|
|
||||||
{
|
|
||||||
_ = this.ApplyDrawableAsync(toolBarItem, ToolbarItem.IconImageSourceProperty, Context, iconDrawable =>
|
|
||||||
{
|
|
||||||
if (iconDrawable != null)
|
|
||||||
{
|
|
||||||
if (!menuItem.IsEnabled)
|
|
||||||
{
|
|
||||||
iconDrawable.Mutate().SetAlpha(DefaultDisabledToolbarAlpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
menuItem.SetIcon(iconDrawable);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateToolbar()
|
void UpdateToolbar()
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Android.Views;
|
||||||
|
using AToolbar = Android.Support.V7.Widget.Toolbar;
|
||||||
|
using ATextView = global::Android.Widget.TextView;
|
||||||
|
using Android.Content;
|
||||||
|
using Android.Graphics;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Platform.Android
|
||||||
|
{
|
||||||
|
internal static class ToolbarExtensions
|
||||||
|
{
|
||||||
|
const int DefaultDisabledToolbarAlpha = 127;
|
||||||
|
public static void DisposeMenuItems(this AToolbar toolbar, IEnumerable<ToolbarItem> toolbarItems, PropertyChangedEventHandler toolbarItemChanged)
|
||||||
|
{
|
||||||
|
if (toolbarItems == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var item in toolbarItems)
|
||||||
|
item.PropertyChanged -= toolbarItemChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateMenuItems(this AToolbar toolbar,
|
||||||
|
IEnumerable<ToolbarItem> toolbarItems,
|
||||||
|
Context context,
|
||||||
|
Color? tintColor,
|
||||||
|
PropertyChangedEventHandler toolbarItemChanged
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (toolbarItems == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var menu = toolbar.Menu;
|
||||||
|
menu.Clear();
|
||||||
|
|
||||||
|
foreach (var item in toolbarItems)
|
||||||
|
{
|
||||||
|
item.PropertyChanged -= toolbarItemChanged;
|
||||||
|
item.PropertyChanged += toolbarItemChanged;
|
||||||
|
|
||||||
|
using (var title = new Java.Lang.String(item.Text))
|
||||||
|
{
|
||||||
|
var menuitem = menu.Add(global::Android.Views.Menu.None, 0, item.Priority, title);
|
||||||
|
menuitem.SetEnabled(item.IsEnabled);
|
||||||
|
menuitem.SetTitleOrContentDescription(item);
|
||||||
|
UpdateMenuItemIcon(context, menuitem, item, tintColor);
|
||||||
|
|
||||||
|
if (item.Order != ToolbarItemOrder.Secondary)
|
||||||
|
menuitem.SetShowAsAction(ShowAsAction.Always);
|
||||||
|
|
||||||
|
menuitem.SetOnMenuItemClickListener(new GenericMenuClickListener(((IMenuItemController)item).Activate));
|
||||||
|
|
||||||
|
if (tintColor != null && tintColor != Color.Default)
|
||||||
|
{
|
||||||
|
var view = toolbar.FindViewById(menuitem.ItemId);
|
||||||
|
if (view is ATextView textView)
|
||||||
|
{
|
||||||
|
if (item.IsEnabled)
|
||||||
|
textView.SetTextColor(tintColor.Value.ToAndroid());
|
||||||
|
else
|
||||||
|
textView.SetTextColor(tintColor.Value.MultiplyAlpha(0.302).ToAndroid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuitem.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem, Color? tintColor)
|
||||||
|
{
|
||||||
|
_ = context.ApplyDrawableAsync(toolBarItem, ToolbarItem.IconImageSourceProperty, baseDrawable =>
|
||||||
|
{
|
||||||
|
if (baseDrawable != null)
|
||||||
|
{
|
||||||
|
using (var constant = baseDrawable.GetConstantState())
|
||||||
|
using (var newDrawable = constant.NewDrawable())
|
||||||
|
using (var iconDrawable = newDrawable.Mutate())
|
||||||
|
{
|
||||||
|
if(tintColor != null)
|
||||||
|
iconDrawable.SetColorFilter(tintColor.Value.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
|
||||||
|
|
||||||
|
if (!menuItem.IsEnabled)
|
||||||
|
{
|
||||||
|
iconDrawable.Mutate().SetAlpha(DefaultDisabledToolbarAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuItem.SetIcon(iconDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void OnToolbarItemPropertyChanged(
|
||||||
|
this AToolbar toolbar,
|
||||||
|
PropertyChangedEventArgs e,
|
||||||
|
IEnumerable<ToolbarItem> toolbarItems,
|
||||||
|
Context context,
|
||||||
|
Color? tintColor,
|
||||||
|
PropertyChangedEventHandler toolbarItemChanged)
|
||||||
|
{
|
||||||
|
if (toolbarItems == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (e.IsOneOf(MenuItem.TextProperty, MenuItem.IconImageSourceProperty, MenuItem.IsEnabledProperty))
|
||||||
|
{
|
||||||
|
toolbar.UpdateMenuItems(toolbarItems, context, tintColor, toolbarItemChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,14 +51,21 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
var oldImageElementManager = e.OldElement as IImageElement;
|
var oldImageElementManager = e.OldElement as IImageElement;
|
||||||
var rendererController = renderer as IImageRendererController;
|
var rendererController = renderer as IImageRendererController;
|
||||||
|
|
||||||
|
if (rendererController.IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
await TryUpdateBitmap(rendererController, view, newImageElementManager, oldImageElementManager);
|
await TryUpdateBitmap(rendererController, view, newImageElementManager, oldImageElementManager);
|
||||||
|
|
||||||
|
if (rendererController.IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
UpdateAspect(rendererController, view, newImageElementManager, oldImageElementManager);
|
UpdateAspect(rendererController, view, newImageElementManager, oldImageElementManager);
|
||||||
|
|
||||||
if (!rendererController.IsDisposed)
|
if (rendererController.IsDisposed)
|
||||||
{
|
return;
|
||||||
|
|
||||||
ElevationHelper.SetElevation(view, renderer.Element);
|
ElevationHelper.SetElevation(view, renderer.Element);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async static void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
async static void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
@ -136,6 +143,9 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
imageController.SetIsLoading(false);
|
imageController.SetIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rendererController.IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
if (Control.Drawable is FormsAnimationDrawable updatedAnimation)
|
if (Control.Drawable is FormsAnimationDrawable updatedAnimation)
|
||||||
{
|
{
|
||||||
rendererController.SetFormsAnimationDrawable(updatedAnimation);
|
rendererController.SetFormsAnimationDrawable(updatedAnimation);
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
|
readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
|
||||||
IFormsAnimationDrawable _formsAnimationDrawable;
|
IFormsAnimationDrawable _formsAnimationDrawable;
|
||||||
|
|
||||||
bool IImageRendererController.IsDisposed => _disposed;
|
bool IImageRendererController.IsDisposed => _disposed || !Control.IsAlive();
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
if (_disposed)
|
||||||
|
|
|
@ -249,7 +249,6 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
|
||||||
|
|
||||||
e.NewElement.PropertyChanged += OnElementPropertyChanged;
|
e.NewElement.PropertyChanged += OnElementPropertyChanged;
|
||||||
|
|
||||||
SkipNextInvalidate();
|
|
||||||
UpdateText();
|
UpdateText();
|
||||||
UpdateLineHeight();
|
UpdateLineHeight();
|
||||||
UpdateCharacterSpacing();
|
UpdateCharacterSpacing();
|
||||||
|
|
|
@ -405,14 +405,15 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
|
var toolbarItems = _toolbarTracker.ToolbarItems;
|
||||||
|
foreach (ToolbarItem item in toolbarItems)
|
||||||
item.PropertyChanged -= HandleToolbarItemPropertyChanged;
|
item.PropertyChanged -= HandleToolbarItemPropertyChanged;
|
||||||
menu.Clear();
|
menu.Clear();
|
||||||
|
|
||||||
if (!ShouldShowActionBarTitleArea())
|
if (!ShouldShowActionBarTitleArea())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
|
foreach (ToolbarItem item in toolbarItems)
|
||||||
{
|
{
|
||||||
IMenuItemController controller = item;
|
IMenuItemController controller = item;
|
||||||
item.PropertyChanged += HandleToolbarItemPropertyChanged;
|
item.PropertyChanged += HandleToolbarItemPropertyChanged;
|
||||||
|
|
|
@ -38,6 +38,8 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
|
|
||||||
public class FormsAnimationDrawable : AnimationDrawable, IFormsAnimationDrawable
|
public class FormsAnimationDrawable : AnimationDrawable, IFormsAnimationDrawable
|
||||||
{
|
{
|
||||||
|
const int DefaultBufferSize = 4096;
|
||||||
|
|
||||||
int _repeatCounter = 0;
|
int _repeatCounter = 0;
|
||||||
int _frameCount = 0;
|
int _frameCount = 0;
|
||||||
bool _finished = false;
|
bool _finished = false;
|
||||||
|
@ -192,28 +194,19 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
InJustDecodeBounds = true
|
InJustDecodeBounds = true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!FileImageSourceHandler.DecodeSynchronously)
|
int drawableIdentifier = ResourceManager.GetDrawableByName(file);
|
||||||
await BitmapFactory.DecodeResourceAsync(context.Resources, ResourceManager.GetDrawableByName(file), options);
|
|
||||||
else
|
|
||||||
BitmapFactory.DecodeResource(context.Resources, ResourceManager.GetDrawableByName(file), options);
|
|
||||||
|
|
||||||
using (var stream = context.Resources.OpenRawResource(ResourceManager.GetDrawableByName(file)))
|
if (drawableIdentifier != 0)
|
||||||
using (var decoder = new AndroidGIFImageParser(context, options.InDensity, options.InTargetDensity))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if (!FileImageSourceHandler.DecodeSynchronously)
|
if (!FileImageSourceHandler.DecodeSynchronously)
|
||||||
await decoder.ParseAsync(stream).ConfigureAwait(false);
|
await BitmapFactory.DecodeResourceAsync(context.Resources, drawableIdentifier, options);
|
||||||
else
|
else
|
||||||
decoder.ParseAsync(stream).Wait();
|
BitmapFactory.DecodeResource(context.Resources, drawableIdentifier, options);
|
||||||
|
|
||||||
animation = decoder.Animation;
|
animation = await GetFormsAnimationDrawableFromResource(drawableIdentifier, context, options);
|
||||||
}
|
|
||||||
catch (GIFDecoderFormatException)
|
|
||||||
{
|
|
||||||
animation = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
animation = await GetFormsAnimationDrawableFromFile(file, context, options);
|
||||||
|
|
||||||
if (animation == null)
|
if (animation == null)
|
||||||
{
|
{
|
||||||
|
@ -264,6 +257,50 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
|
|
||||||
return animation;
|
return animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static async Task<FormsAnimationDrawable> GetFormsAnimationDrawableFromResource(int resourceId, Context context, BitmapFactory.Options options)
|
||||||
|
{
|
||||||
|
FormsAnimationDrawable animation = null;
|
||||||
|
|
||||||
|
using (var stream = context.Resources.OpenRawResource(resourceId))
|
||||||
|
animation = await GetFormsAnimationDrawableFromStream(stream, context, options);
|
||||||
|
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<FormsAnimationDrawable> GetFormsAnimationDrawableFromFile(string file, Context context, BitmapFactory.Options options)
|
||||||
|
{
|
||||||
|
FormsAnimationDrawable animation = null;
|
||||||
|
|
||||||
|
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultBufferSize, true))
|
||||||
|
animation = await GetFormsAnimationDrawableFromStream(stream, context, options);
|
||||||
|
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static async Task<FormsAnimationDrawable> GetFormsAnimationDrawableFromStream(Stream stream, Context context, BitmapFactory.Options options)
|
||||||
|
{
|
||||||
|
FormsAnimationDrawable animation = null;
|
||||||
|
|
||||||
|
using (var decoder = new AndroidGIFImageParser(context, options.InDensity, options.InTargetDensity))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!FileImageSourceHandler.DecodeSynchronously)
|
||||||
|
await decoder.ParseAsync(stream).ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
decoder.ParseAsync(stream).Wait();
|
||||||
|
|
||||||
|
animation = decoder.Animation;
|
||||||
|
}
|
||||||
|
catch (GIFDecoderFormatException)
|
||||||
|
{
|
||||||
|
animation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AndroidGIFImageParser : GIFImageParser, IDisposable
|
class AndroidGIFImageParser : GIFImageParser, IDisposable
|
||||||
|
|
|
@ -39,6 +39,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool IImageRendererController.IsDisposed => false;
|
bool IImageRendererController.IsDisposed => false || !this.IsAlive();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,34 +8,28 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
{
|
{
|
||||||
public class FormsTextView : TextView
|
public class FormsTextView : TextView
|
||||||
{
|
{
|
||||||
bool _skip;
|
|
||||||
|
|
||||||
public FormsTextView(Context context) : base(context)
|
public FormsTextView(Context context) : base(context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
public FormsTextView(Context context, IAttributeSet attrs) : base(context, attrs)
|
public FormsTextView(Context context, IAttributeSet attrs) : base(context, attrs)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
public FormsTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
|
public FormsTextView(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
protected FormsTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
|
protected FormsTextView(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Invalidate()
|
[Obsolete]
|
||||||
{
|
|
||||||
if (!_skip)
|
|
||||||
base.Invalidate();
|
|
||||||
_skip = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SkipNextInvalidate()
|
public void SkipNextInvalidate()
|
||||||
{
|
{
|
||||||
_skip = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -125,7 +125,6 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_view.SkipNextInvalidate();
|
|
||||||
UpdateText();
|
UpdateText();
|
||||||
if (e.OldElement.LineBreakMode != e.NewElement.LineBreakMode)
|
if (e.OldElement.LineBreakMode != e.NewElement.LineBreakMode)
|
||||||
UpdateLineBreakMode();
|
UpdateLineBreakMode();
|
||||||
|
|
|
@ -19,6 +19,8 @@ using Toolbar = Android.Support.V7.Widget.Toolbar;
|
||||||
using ADrawableCompat = Android.Support.V4.Graphics.Drawable.DrawableCompat;
|
using ADrawableCompat = Android.Support.V4.Graphics.Drawable.DrawableCompat;
|
||||||
using ATextView = global::Android.Widget.TextView;
|
using ATextView = global::Android.Widget.TextView;
|
||||||
using Android.Support.Design.Widget;
|
using Android.Support.Design.Widget;
|
||||||
|
using AColor = Android.Graphics.Color;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
|
||||||
namespace Xamarin.Forms.Platform.Android
|
namespace Xamarin.Forms.Platform.Android
|
||||||
{
|
{
|
||||||
|
@ -154,11 +156,8 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
if (_backButtonBehavior != null)
|
if (_backButtonBehavior != null)
|
||||||
_backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged;
|
_backButtonBehavior.PropertyChanged -= OnBackButtonBehaviorChanged;
|
||||||
|
|
||||||
if(Page?.ToolbarItems?.Count > 0)
|
|
||||||
{
|
_toolbar.DisposeMenuItems(Page?.ToolbarItems, OnToolbarItemPropertyChanged);
|
||||||
foreach (var item in Page.ToolbarItems)
|
|
||||||
item.PropertyChanged -= OnToolbarItemPropertyChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
((IShellController)_shellContext?.Shell)?.RemoveFlyoutBehaviorObserver(this);
|
((IShellController)_shellContext?.Shell)?.RemoveFlyoutBehaviorObserver(this);
|
||||||
|
|
||||||
|
@ -492,37 +491,7 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
protected virtual void UpdateToolbarItems(Toolbar toolbar, Page page)
|
protected virtual void UpdateToolbarItems(Toolbar toolbar, Page page)
|
||||||
{
|
{
|
||||||
var menu = toolbar.Menu;
|
var menu = toolbar.Menu;
|
||||||
menu.Clear();
|
toolbar.UpdateMenuItems(page.ToolbarItems, _shellContext.AndroidContext, TintColor, OnToolbarItemPropertyChanged);
|
||||||
|
|
||||||
foreach (var item in page.ToolbarItems)
|
|
||||||
{
|
|
||||||
item.PropertyChanged -= OnToolbarItemPropertyChanged;
|
|
||||||
item.PropertyChanged += OnToolbarItemPropertyChanged;
|
|
||||||
|
|
||||||
using (var title = new Java.Lang.String(item.Text))
|
|
||||||
{
|
|
||||||
var menuitem = menu.Add(title);
|
|
||||||
UpdateMenuItemIcon(_shellContext.AndroidContext, menuitem, item);
|
|
||||||
|
|
||||||
menuitem.SetTitleOrContentDescription(item);
|
|
||||||
menuitem.SetEnabled(item.IsEnabled);
|
|
||||||
|
|
||||||
if (item.Order != ToolbarItemOrder.Secondary)
|
|
||||||
menuitem.SetShowAsAction(ShowAsAction.Always);
|
|
||||||
|
|
||||||
menuitem.SetOnMenuItemClickListener(new GenericMenuClickListener(((IMenuItemController)item).Activate));
|
|
||||||
|
|
||||||
if (TintColor != Color.Default)
|
|
||||||
{
|
|
||||||
var view = toolbar.FindViewById(menuitem.ItemId);
|
|
||||||
if (view is ATextView textView)
|
|
||||||
textView.SetTextColor(TintColor.ToAndroid());
|
|
||||||
}
|
|
||||||
|
|
||||||
menuitem.Dispose();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchHandler = Shell.GetSearchHandler(page);
|
SearchHandler = Shell.GetSearchHandler(page);
|
||||||
if (SearchHandler != null && SearchHandler.SearchBoxVisibility != SearchBoxVisibility.Hidden)
|
if (SearchHandler != null && SearchHandler.SearchBoxVisibility != SearchBoxVisibility.Hidden)
|
||||||
|
@ -585,10 +554,7 @@ namespace Xamarin.Forms.Platform.Android
|
||||||
|
|
||||||
void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
|
void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PropertyName == MenuItem.TextProperty.PropertyName)
|
_toolbar.OnToolbarItemPropertyChanged(e, Page.ToolbarItems, _shellContext.AndroidContext, TintColor, OnToolbarItemPropertyChanged);
|
||||||
UpdateToolbarItems();
|
|
||||||
if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
|
|
||||||
UpdateToolbarItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSearchViewAttachedToWindow(object sender, AView.ViewAttachedToWindowEventArgs e)
|
void OnSearchViewAttachedToWindow(object sender, AView.ViewAttachedToWindowEventArgs e)
|
||||||
|
|
|
@ -143,10 +143,12 @@ namespace Xamarin.Forms.Platform.MacOS
|
||||||
AllowsUserCustomization = false,
|
AllowsUserCustomization = false,
|
||||||
ShowsBaselineSeparator = true,
|
ShowsBaselineSeparator = true,
|
||||||
SizeMode = NSToolbarSizeMode.Regular,
|
SizeMode = NSToolbarSizeMode.Regular,
|
||||||
Delegate = this,
|
Delegate = this
|
||||||
CenteredItemIdentifier = TitleGroupIdentifier
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (Forms.IsMojaveOrNewer)
|
||||||
|
toolbar.CenteredItemIdentifier = TitleGroupIdentifier;
|
||||||
|
|
||||||
return toolbar;
|
return toolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,34 @@
|
||||||
|
using EImage = ElmSharp.Image;
|
||||||
|
|
||||||
namespace Xamarin.Forms.Platform.Tizen
|
namespace Xamarin.Forms.Platform.Tizen
|
||||||
{
|
{
|
||||||
internal static class ImageExtensions
|
public static class ImageExtensions
|
||||||
{
|
{
|
||||||
internal static bool IsNullOrEmpty(this ImageSource imageSource) =>
|
public static void ApplyAspect(this EImage image, Aspect aspect)
|
||||||
|
{
|
||||||
|
Aspect _aspect = aspect;
|
||||||
|
|
||||||
|
switch (_aspect)
|
||||||
|
{
|
||||||
|
case Aspect.AspectFit:
|
||||||
|
image.IsFixedAspect = true;
|
||||||
|
image.CanFillOutside = false;
|
||||||
|
break;
|
||||||
|
case Aspect.AspectFill:
|
||||||
|
image.IsFixedAspect = true;
|
||||||
|
image.CanFillOutside = true;
|
||||||
|
break;
|
||||||
|
case Aspect.Fill:
|
||||||
|
image.IsFixedAspect = false;
|
||||||
|
image.CanFillOutside = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Log.Warn("Invalid Aspect value: {0}", _aspect);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsNullOrEmpty(this ImageSource imageSource) =>
|
||||||
imageSource == null || imageSource.IsEmpty;
|
imageSource == null || imageSource.IsEmpty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +1,222 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Threading.Tasks;
|
||||||
using ElmSharp;
|
using ElmSharp;
|
||||||
using Xamarin.Forms.Internals;
|
using Xamarin.Forms.Internals;
|
||||||
|
using EColor = ElmSharp.Color;
|
||||||
|
|
||||||
namespace Xamarin.Forms.Platform.Tizen
|
namespace Xamarin.Forms.Platform.Tizen
|
||||||
{
|
{
|
||||||
public class LightweightPlatform : BindableObject, ITizenPlatform
|
public class LightweightPlatform : ITizenPlatform, INavigation, IDisposable
|
||||||
{
|
{
|
||||||
Page _page;
|
NavigationModel _navModel = new NavigationModel();
|
||||||
EvasObject _rootView;
|
Native.Canvas _viewStack;
|
||||||
bool _disposed;
|
readonly PopupManager _popupManager;
|
||||||
|
bool _hasAlpha;
|
||||||
|
readonly EColor _defaultPlatformColor;
|
||||||
|
|
||||||
internal LightweightPlatform(EvasObject parent)
|
public LightweightPlatform(EvasObject parent)
|
||||||
{
|
{
|
||||||
Forms.NativeParent = parent;
|
Forms.NativeParent = parent;
|
||||||
|
_defaultPlatformColor = Device.Idiom == TargetIdiom.Phone ? EColor.White : EColor.Transparent;
|
||||||
|
_viewStack = new Native.Canvas(parent)
|
||||||
|
{
|
||||||
|
BackgroundColor = _defaultPlatformColor,
|
||||||
|
};
|
||||||
|
_viewStack.SetAlignment(-1, -1);
|
||||||
|
_viewStack.SetWeight(1.0, 1.0);
|
||||||
|
_viewStack.LayoutUpdated += OnLayout;
|
||||||
|
_viewStack.Show();
|
||||||
|
|
||||||
|
if (Forms.UseMessagingCenter)
|
||||||
|
{
|
||||||
|
_popupManager = new PopupManager(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable 0067
|
||||||
public event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged;
|
public event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged;
|
||||||
|
#pragma warning restore 0067
|
||||||
|
|
||||||
public bool HasAlpha { get => false; set { } }
|
public bool HasAlpha
|
||||||
|
{
|
||||||
|
get => _hasAlpha;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_hasAlpha = value;
|
||||||
|
_viewStack.BackgroundColor = _hasAlpha ? EColor.Transparent : _defaultPlatformColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IPageController CurrentPageController => _navModel.CurrentPage as IPageController;
|
||||||
|
|
||||||
|
IReadOnlyList<Page> INavigation.ModalStack => _navModel.Modals.ToList();
|
||||||
|
|
||||||
|
IReadOnlyList<Page> INavigation.NavigationStack => new List<Page>();
|
||||||
|
|
||||||
|
public void SetPage(Page page)
|
||||||
|
{
|
||||||
|
ResetChildren();
|
||||||
|
_navModel = new NavigationModel();
|
||||||
|
if (page == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_navModel.Push(page, null);
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
page.Platform = this;
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
((Application)page.RealParent).NavigationProxy.Inner = this;
|
||||||
|
|
||||||
|
var renderer = Platform.CreateRenderer(page);
|
||||||
|
renderer.NativeView.Geometry = _viewStack.Geometry;
|
||||||
|
_viewStack.Children.Add(renderer.NativeView);
|
||||||
|
|
||||||
|
CurrentPageController?.SendAppearing();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SendBackButtonPressed()
|
||||||
|
{
|
||||||
|
return _navModel?.CurrentPage?.SendBackButtonPressed() ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvasObject GetRootNativeView()
|
||||||
|
{
|
||||||
|
return _viewStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PageIsChildOfPlatform(Page page)
|
||||||
|
{
|
||||||
|
var parent = page.AncestorToRoot();
|
||||||
|
return _navModel.Modals.FirstOrDefault() == page || _navModel.Roots.Contains(parent);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EvasObject GetRootNativeView() => _rootView;
|
|
||||||
|
|
||||||
public bool SendBackButtonPressed()
|
|
||||||
{
|
|
||||||
if (_page == null) return false;
|
|
||||||
return _page.SendBackButtonPressed();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPage(Page page)
|
|
||||||
{
|
|
||||||
if (_page == page) return;
|
|
||||||
if (_page != null)
|
|
||||||
{
|
|
||||||
var oldRenderer = Platform.GetRenderer(_page);
|
|
||||||
oldRenderer?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
_page = page;
|
|
||||||
|
|
||||||
if (_page == null) return;
|
|
||||||
|
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
|
||||||
// The Platform property is no longer necessary, but we have to set it because some third-party
|
|
||||||
// library might still be retrieving it and using it
|
|
||||||
_page.Platform = this;
|
|
||||||
#pragma warning restore CS0618 // Type or member is obsolete
|
|
||||||
|
|
||||||
var renderer = Platform.CreateRenderer(_page);
|
|
||||||
_rootView = renderer.NativeView;
|
|
||||||
RootNativeViewChanged?.Invoke(this, new RootNativeViewChangedEventArgs(_rootView));
|
|
||||||
_rootView.Show();
|
|
||||||
|
|
||||||
Device.StartTimer(TimeSpan.Zero, () =>
|
|
||||||
{
|
|
||||||
_page?.SendAppearing();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnBindingContextChanged()
|
|
||||||
{
|
|
||||||
BindableObject.SetInheritedBindingContext(_page, base.BindingContext);
|
|
||||||
base.OnBindingContextChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_disposed) return;
|
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
SetPage(null);
|
_popupManager?.Dispose();
|
||||||
|
_viewStack?.Unrealize();
|
||||||
}
|
}
|
||||||
_disposed = true;
|
}
|
||||||
|
|
||||||
|
Task<Page> INavigation.PopModalAsync()
|
||||||
|
{
|
||||||
|
return (this as INavigation).PopModalAsync(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task<Page> INavigation.PopModalAsync(bool animated)
|
||||||
|
{
|
||||||
|
Page page = _navModel.PopModal();
|
||||||
|
(page as IPageController)?.SendDisappearing();
|
||||||
|
|
||||||
|
var renderer = Platform.GetRenderer(page);
|
||||||
|
_viewStack.Children.Remove(renderer.NativeView);
|
||||||
|
renderer.Dispose();
|
||||||
|
|
||||||
|
_viewStack.Children.LastOrDefault()?.Show();
|
||||||
|
|
||||||
|
CurrentPageController?.SendAppearing();
|
||||||
|
return Task.FromResult(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task INavigation.PushModalAsync(Page modal)
|
||||||
|
{
|
||||||
|
return (this as INavigation).PushModalAsync(modal, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task INavigation.PushModalAsync(Page page, bool animated)
|
||||||
|
{
|
||||||
|
var previousPage = CurrentPageController;
|
||||||
|
previousPage?.SendDisappearing();
|
||||||
|
|
||||||
|
_navModel.PushModal(page);
|
||||||
|
|
||||||
|
var lastTop = _viewStack.Children.LastOrDefault();
|
||||||
|
|
||||||
|
var renderer = Platform.GetOrCreateRenderer(page);
|
||||||
|
renderer.NativeView.Geometry = _viewStack.Geometry;
|
||||||
|
|
||||||
|
_viewStack.Children.Add(renderer.NativeView);
|
||||||
|
if (lastTop != null)
|
||||||
|
{
|
||||||
|
lastTop.Hide();
|
||||||
|
renderer.NativeView.StackAbove(lastTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the modal is still on the stack
|
||||||
|
if (_navModel.CurrentPage == page)
|
||||||
|
CurrentPageController.SendAppearing();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void INavigation.InsertPageBefore(Page page, Page before)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("InsertPageBefore is not supported globally on Tizen, please use a NavigationPage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Task<Page> INavigation.PopAsync()
|
||||||
|
{
|
||||||
|
return ((INavigation)this).PopAsync(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task<Page> INavigation.PopAsync(bool animated)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("PopAsync is not supported globally on Tizen, please use a NavigationPage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Task INavigation.PopToRootAsync()
|
||||||
|
{
|
||||||
|
return ((INavigation)this).PopToRootAsync(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task INavigation.PopToRootAsync(bool animated)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("PopToRootAsync is not supported globally on Tizen, please use a NavigationPage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Task INavigation.PushAsync(Page root)
|
||||||
|
{
|
||||||
|
return ((INavigation)this).PushAsync(root, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Task INavigation.PushAsync(Page root, bool animated)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("PushAsync is not supported globally on Tizen, please use a NavigationPage.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void INavigation.RemovePage(Page page)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("RemovePage is not supported globally on Tizen, please use a NavigationPage.");
|
||||||
}
|
}
|
||||||
|
|
||||||
SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
|
SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
|
||||||
{
|
{
|
||||||
return Platform.GetNativeSize(view, widthConstraint, heightConstraint);
|
return Platform.GetNativeSize(view, widthConstraint, heightConstraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnLayout(object sender, Native.LayoutEventArgs e)
|
||||||
|
{
|
||||||
|
foreach (var child in _viewStack.Children)
|
||||||
|
{
|
||||||
|
child.Geometry = _viewStack.Geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetChildren()
|
||||||
|
{
|
||||||
|
var children = _viewStack.Children.ToList();
|
||||||
|
_viewStack.Children.Clear();
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
child.Unrealize();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,39 +10,12 @@ namespace Xamarin.Forms.Platform.Tizen.Native
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Image : EImage, IMeasurable
|
public class Image : EImage, IMeasurable
|
||||||
{
|
{
|
||||||
Aspect _aspect;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Image"/> class.
|
/// Initializes a new instance of the <see cref="Xamarin.Forms.Platform.Tizen.Native.Image"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parent">The parent EvasObject.</param>
|
/// <param name="parent">The parent EvasObject.</param>
|
||||||
public Image(EvasObject parent) : base(parent)
|
public Image(EvasObject parent) : base(parent)
|
||||||
{
|
{
|
||||||
IsScaling = true;
|
|
||||||
CanScaleUp = true;
|
|
||||||
CanScaleDown = true;
|
|
||||||
|
|
||||||
ApplyAspect(Aspect.AspectFit);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the image aspect ratio preserving option.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>The aspect option.</value>
|
|
||||||
public Aspect Aspect
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _aspect;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_aspect != value)
|
|
||||||
{
|
|
||||||
ApplyAspect(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -67,6 +40,15 @@ namespace Xamarin.Forms.Platform.Tizen.Native
|
||||||
return isLoadComplate;
|
return isLoadComplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool LoadFromFile(string file)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(file))
|
||||||
|
{
|
||||||
|
return Load(ResourcePath.GetPath(file));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements the <see cref="Xamarin.Forms.Platform.Tizen.Native.IMeasurable"/> interface.
|
/// Implements the <see cref="Xamarin.Forms.Platform.Tizen.Native.IMeasurable"/> interface.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -75,7 +57,6 @@ namespace Xamarin.Forms.Platform.Tizen.Native
|
||||||
public ESize Measure(int availableWidth, int availableHeight)
|
public ESize Measure(int availableWidth, int availableHeight)
|
||||||
{
|
{
|
||||||
var imageSize = ObjectSize;
|
var imageSize = ObjectSize;
|
||||||
|
|
||||||
var size = new ESize()
|
var size = new ESize()
|
||||||
{
|
{
|
||||||
Width = imageSize.Width,
|
Width = imageSize.Width,
|
||||||
|
@ -96,36 +77,5 @@ namespace Xamarin.Forms.Platform.Tizen.Native
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the <c>IsFixedAspect</c> and <c>CanFillOutside</c> properties according to the given <paramref name="aspect"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="aspect">The aspect setting to be applied to the image.</param>
|
|
||||||
void ApplyAspect(Aspect aspect)
|
|
||||||
{
|
|
||||||
_aspect = aspect;
|
|
||||||
|
|
||||||
switch (_aspect)
|
|
||||||
{
|
|
||||||
case Aspect.AspectFit:
|
|
||||||
IsFixedAspect = true;
|
|
||||||
CanFillOutside = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Aspect.AspectFill:
|
|
||||||
IsFixedAspect = true;
|
|
||||||
CanFillOutside = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Aspect.Fill:
|
|
||||||
IsFixedAspect = false;
|
|
||||||
CanFillOutside = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
Log.Warn("Invalid Aspect value: {0}", _aspect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,15 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using Xamarin.Forms.Internals;
|
using System.Linq;
|
||||||
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using ElmSharp;
|
using ElmSharp;
|
||||||
using EProgressBar = ElmSharp.ProgressBar;
|
using Xamarin.Forms.Internals;
|
||||||
using EButton = ElmSharp.Button;
|
|
||||||
using EColor = ElmSharp.Color;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Xamarin.Forms.Material")]
|
[assembly: InternalsVisibleTo("Xamarin.Forms.Material")]
|
||||||
|
|
||||||
|
@ -85,6 +81,7 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
EvasObject GetRootNativeView();
|
EvasObject GetRootNativeView();
|
||||||
bool HasAlpha { get; set; }
|
bool HasAlpha { get; set; }
|
||||||
event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged;
|
event EventHandler<RootNativeViewChangedEventArgs> RootNativeViewChanged;
|
||||||
|
bool PageIsChildOfPlatform(Page page);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RootNativeViewChangedEventArgs : EventArgs
|
public class RootNativeViewChangedEventArgs : EventArgs
|
||||||
|
@ -97,9 +94,8 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
{
|
{
|
||||||
NavigationModel _navModel = new NavigationModel();
|
NavigationModel _navModel = new NavigationModel();
|
||||||
bool _disposed;
|
bool _disposed;
|
||||||
Native.Dialog _pageBusyDialog;
|
|
||||||
int _pageBusyCount;
|
|
||||||
readonly Naviframe _internalNaviframe;
|
readonly Naviframe _internalNaviframe;
|
||||||
|
readonly PopupManager _popupManager;
|
||||||
|
|
||||||
readonly HashSet<EvasObject> _alerts = new HashSet<EvasObject>();
|
readonly HashSet<EvasObject> _alerts = new HashSet<EvasObject>();
|
||||||
|
|
||||||
|
@ -110,14 +106,6 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
internal DefaultPlatform(EvasObject parent)
|
internal DefaultPlatform(EvasObject parent)
|
||||||
{
|
{
|
||||||
Forms.NativeParent = parent;
|
Forms.NativeParent = parent;
|
||||||
_pageBusyCount = 0;
|
|
||||||
if (Forms.UseMessagingCenter)
|
|
||||||
{
|
|
||||||
MessagingCenter.Subscribe<Page, bool>(this, Page.BusySetSignalName, BusySetSignalNameHandler);
|
|
||||||
MessagingCenter.Subscribe<Page, AlertArguments>(this, Page.AlertSignalName, AlertSignalNameHandler);
|
|
||||||
MessagingCenter.Subscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName, ActionSheetSignalNameHandler);
|
|
||||||
MessagingCenter.Subscribe<Page, PromptArguments>(this, Page.PromptSignalName, OnPromptRequested);
|
|
||||||
}
|
|
||||||
|
|
||||||
_internalNaviframe = new Naviframe(Forms.NativeParent)
|
_internalNaviframe = new Naviframe(Forms.NativeParent)
|
||||||
{
|
{
|
||||||
|
@ -128,6 +116,11 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
_internalNaviframe.SetWeight(1.0, 1.0);
|
_internalNaviframe.SetWeight(1.0, 1.0);
|
||||||
_internalNaviframe.Show();
|
_internalNaviframe.Show();
|
||||||
_internalNaviframe.AnimationFinished += NaviAnimationFinished;
|
_internalNaviframe.AnimationFinished += NaviAnimationFinished;
|
||||||
|
|
||||||
|
if (Forms.UseMessagingCenter)
|
||||||
|
{
|
||||||
|
_popupManager = new PopupManager(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~DefaultPlatform()
|
~DefaultPlatform()
|
||||||
|
@ -224,18 +217,18 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
return _internalNaviframe as EvasObject;
|
return _internalNaviframe as EvasObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool PageIsChildOfPlatform(Page page)
|
||||||
|
{
|
||||||
|
var parent = page.AncestorToRoot();
|
||||||
|
return Page == parent || _navModel.Roots.Contains(parent);
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_disposed) return;
|
if (_disposed) return;
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
if (Forms.UseMessagingCenter)
|
_popupManager?.Dispose();
|
||||||
{
|
|
||||||
MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
|
|
||||||
MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
|
|
||||||
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
|
|
||||||
MessagingCenter.Unsubscribe<Page, PromptArguments>(this, Page.PromptSignalName);
|
|
||||||
}
|
|
||||||
SetPage(null);
|
SetPage(null);
|
||||||
_internalNaviframe.Unrealize();
|
_internalNaviframe.Unrealize();
|
||||||
}
|
}
|
||||||
|
@ -405,263 +398,6 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
tcs?.SetResult(true);
|
tcs?.SetResult(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BusySetSignalNameHandler(Page sender, bool enabled)
|
|
||||||
{
|
|
||||||
// Verify that the page making the request is child of this platform
|
|
||||||
if (!PageIsChildOfPlatform(sender))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (null == _pageBusyDialog)
|
|
||||||
{
|
|
||||||
_pageBusyDialog = new Native.Dialog(Forms.NativeParent)
|
|
||||||
{
|
|
||||||
Orientation = PopupOrientation.Center,
|
|
||||||
BackgroundColor = EColor.Transparent
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Device.Idiom == TargetIdiom.Phone)
|
|
||||||
{
|
|
||||||
_pageBusyDialog.SetPartColor("bg_title", EColor.Transparent);
|
|
||||||
_pageBusyDialog.SetPartColor("bg_content", EColor.Transparent);
|
|
||||||
}
|
|
||||||
else if (Device.Idiom == TargetIdiom.Watch)
|
|
||||||
{
|
|
||||||
_pageBusyDialog.Style = "circle";
|
|
||||||
}
|
|
||||||
|
|
||||||
var activity = new EProgressBar(_pageBusyDialog)
|
|
||||||
{
|
|
||||||
Style = "process_large",
|
|
||||||
IsPulseMode = true,
|
|
||||||
};
|
|
||||||
activity.PlayPulse();
|
|
||||||
activity.Show();
|
|
||||||
|
|
||||||
_pageBusyDialog.Content = activity;
|
|
||||||
|
|
||||||
}
|
|
||||||
_pageBusyCount = Math.Max(0, enabled ? _pageBusyCount + 1 : _pageBusyCount - 1);
|
|
||||||
if (_pageBusyCount > 0)
|
|
||||||
{
|
|
||||||
_pageBusyDialog.Show();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_pageBusyDialog.Dismiss();
|
|
||||||
_pageBusyDialog = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlertSignalNameHandler(Page sender, AlertArguments arguments)
|
|
||||||
{
|
|
||||||
// Verify that the page making the request is child of this platform
|
|
||||||
if (!PageIsChildOfPlatform(sender))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Native.Dialog alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null));
|
|
||||||
|
|
||||||
alert.Title = arguments.Title;
|
|
||||||
var message = arguments.Message.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(Environment.NewLine, "<br>");
|
|
||||||
alert.Message = message;
|
|
||||||
|
|
||||||
EButton cancel = new EButton(alert) { Text = arguments.Cancel };
|
|
||||||
alert.NegativeButton = cancel;
|
|
||||||
cancel.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
arguments.SetResult(false);
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (arguments.Accept != null)
|
|
||||||
{
|
|
||||||
EButton ok = new EButton(alert) { Text = arguments.Accept };
|
|
||||||
alert.NeutralButton = ok;
|
|
||||||
ok.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
arguments.SetResult(true);
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
alert.BackButtonPressed += (s, evt) =>
|
|
||||||
{
|
|
||||||
arguments.SetResult(false);
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
alert.Show();
|
|
||||||
_alerts.Add(alert);
|
|
||||||
alert.Dismissed += (s, e) => _alerts.Remove(alert);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionSheetSignalNameHandler(Page sender, ActionSheetArguments arguments)
|
|
||||||
{
|
|
||||||
// Verify that the page making the request is child of this platform
|
|
||||||
if (!PageIsChildOfPlatform(sender))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Native.Dialog alert = Native.Dialog.CreateDialog(Forms.NativeParent);
|
|
||||||
|
|
||||||
alert.Title = arguments.Title;
|
|
||||||
Box box = new Box(alert);
|
|
||||||
|
|
||||||
if (null != arguments.Destruction)
|
|
||||||
{
|
|
||||||
Native.Button destruction = new Native.Button(alert)
|
|
||||||
{
|
|
||||||
Text = arguments.Destruction,
|
|
||||||
Style = ButtonStyle.Text,
|
|
||||||
TextColor = EColor.Red,
|
|
||||||
AlignmentX = -1
|
|
||||||
};
|
|
||||||
destruction.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
arguments.SetResult(arguments.Destruction);
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
destruction.Show();
|
|
||||||
box.PackEnd(destruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string buttonName in arguments.Buttons)
|
|
||||||
{
|
|
||||||
Native.Button button = new Native.Button(alert)
|
|
||||||
{
|
|
||||||
Text = buttonName,
|
|
||||||
Style = ButtonStyle.Text,
|
|
||||||
AlignmentX = -1
|
|
||||||
};
|
|
||||||
button.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
arguments.SetResult(buttonName);
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
button.Show();
|
|
||||||
box.PackEnd(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
box.Show();
|
|
||||||
alert.Content = box;
|
|
||||||
|
|
||||||
if (null != arguments.Cancel)
|
|
||||||
{
|
|
||||||
EButton cancel = new EButton(Forms.NativeParent) { Text = arguments.Cancel };
|
|
||||||
alert.NegativeButton = cancel;
|
|
||||||
cancel.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
alert.BackButtonPressed += (s, evt) =>
|
|
||||||
{
|
|
||||||
alert.Dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
alert.Show();
|
|
||||||
|
|
||||||
_alerts.Add(alert);
|
|
||||||
alert.Dismissed += (s, e) => _alerts.Remove(alert);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnPromptRequested(Page sender, PromptArguments args)
|
|
||||||
{
|
|
||||||
// Verify that the page making the request is child of this platform
|
|
||||||
if (!PageIsChildOfPlatform(sender))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var prompt = Native.Dialog.CreateDialog(Forms.NativeParent, (args.Accept != null));
|
|
||||||
prompt.Title = args.Title;
|
|
||||||
|
|
||||||
var entry = new Entry
|
|
||||||
{
|
|
||||||
MinimumWidthRequest = 200,
|
|
||||||
HorizontalOptions = LayoutOptions.FillAndExpand,
|
|
||||||
BackgroundColor = Color.FromRgb(250, 250, 250),
|
|
||||||
TextColor = Color.Black,
|
|
||||||
Keyboard = args.Keyboard,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(args.Placeholder))
|
|
||||||
{
|
|
||||||
entry.Placeholder = args.Placeholder;
|
|
||||||
}
|
|
||||||
if (args.MaxLength > 0)
|
|
||||||
{
|
|
||||||
entry.MaxLength = args.MaxLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
var layout = new StackLayout
|
|
||||||
{
|
|
||||||
Spacing = 10,
|
|
||||||
Children =
|
|
||||||
{
|
|
||||||
new Label
|
|
||||||
{
|
|
||||||
LineBreakMode = LineBreakMode.CharacterWrap,
|
|
||||||
TextColor = Device.Idiom == TargetIdiom.Watch ? Color.White : Color.Accent,
|
|
||||||
Text = args.Message,
|
|
||||||
HorizontalOptions = LayoutOptions.FillAndExpand,
|
|
||||||
HorizontalTextAlignment = TextAlignment.Center,
|
|
||||||
FontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label)),
|
|
||||||
},
|
|
||||||
entry,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
layout.Parent = sender;
|
|
||||||
var layoutrenderer = Platform.GetOrCreateRenderer(layout);
|
|
||||||
|
|
||||||
var request = layout.Measure(Device.Idiom == TargetIdiom.Watch ? Page.Width * 0.7 : Page.Width, Page.Height);
|
|
||||||
(layoutrenderer as LayoutRenderer).RegisterOnLayoutUpdated();
|
|
||||||
layoutrenderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(request.Request.Height);
|
|
||||||
layoutrenderer.NativeView.MinimumWidth = Forms.ConvertToScaledPixel(request.Request.Width);
|
|
||||||
|
|
||||||
prompt.Content = layoutrenderer.NativeView;
|
|
||||||
|
|
||||||
var cancel = new EButton(prompt) { Text = args.Cancel };
|
|
||||||
prompt.NegativeButton = cancel;
|
|
||||||
cancel.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
args.SetResult(null);
|
|
||||||
prompt.Dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (args.Accept != null)
|
|
||||||
{
|
|
||||||
var ok = new EButton(prompt) { Text = args.Accept };
|
|
||||||
prompt.NeutralButton = ok;
|
|
||||||
ok.Clicked += (s, evt) =>
|
|
||||||
{
|
|
||||||
args.SetResult(entry.Text);
|
|
||||||
prompt.Dismiss();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Completed += (s, e) =>
|
|
||||||
{
|
|
||||||
args.SetResult(entry.Text);
|
|
||||||
prompt.Dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
prompt.BackButtonPressed += (s, evt) =>
|
|
||||||
{
|
|
||||||
args.SetResult(null);
|
|
||||||
prompt.Dismiss();
|
|
||||||
};
|
|
||||||
|
|
||||||
prompt.Show();
|
|
||||||
|
|
||||||
_alerts.Add(prompt);
|
|
||||||
prompt.Dismissed += (s, e) => _alerts.Remove(prompt);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PageIsChildOfPlatform(Page page)
|
|
||||||
{
|
|
||||||
var parent = page.AncestorToRoot();
|
|
||||||
return Page == parent || _navModel.Roots.Contains(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
|
SizeRequest IPlatform.GetNativeSize(VisualElement view, double widthConstraint, double heightConstraint)
|
||||||
{
|
{
|
||||||
return Platform.GetNativeSize(view, widthConstraint, heightConstraint);
|
return Platform.GetNativeSize(view, widthConstraint, heightConstraint);
|
||||||
|
|
|
@ -0,0 +1,295 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using ElmSharp;
|
||||||
|
using Xamarin.Forms.Internals;
|
||||||
|
using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
|
||||||
|
using EButton = ElmSharp.Button;
|
||||||
|
using EColor = ElmSharp.Color;
|
||||||
|
using EProgressBar = ElmSharp.ProgressBar;
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Platform.Tizen
|
||||||
|
{
|
||||||
|
public class PopupManager : IDisposable
|
||||||
|
{
|
||||||
|
ITizenPlatform _platform;
|
||||||
|
Native.Dialog _pageBusyDialog;
|
||||||
|
int _pageBusyCount;
|
||||||
|
readonly HashSet<EvasObject> _alerts = new HashSet<EvasObject>();
|
||||||
|
|
||||||
|
public PopupManager(ITizenPlatform platform)
|
||||||
|
{
|
||||||
|
_platform = platform;
|
||||||
|
MessagingCenter.Subscribe<Page, bool>(this, Page.BusySetSignalName, OnBusySetRequest);
|
||||||
|
MessagingCenter.Subscribe<Page, AlertArguments>(this, Page.AlertSignalName, OnAlertRequest);
|
||||||
|
MessagingCenter.Subscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName, OnActionSheetRequest);
|
||||||
|
MessagingCenter.Subscribe<Page, PromptArguments>(this, Page.PromptSignalName, OnPromptRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
MessagingCenter.Unsubscribe<Page, AlertArguments>(this, Page.AlertSignalName);
|
||||||
|
MessagingCenter.Unsubscribe<Page, bool>(this, Page.BusySetSignalName);
|
||||||
|
MessagingCenter.Unsubscribe<Page, ActionSheetArguments>(this, Page.ActionSheetSignalName);
|
||||||
|
MessagingCenter.Unsubscribe<Page, PromptArguments>(this, Page.PromptSignalName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnBusySetRequest(Page sender, bool enabled)
|
||||||
|
{
|
||||||
|
// Verify that the page making the request is child of this platform
|
||||||
|
if (!_platform.PageIsChildOfPlatform(sender))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (null == _pageBusyDialog)
|
||||||
|
{
|
||||||
|
_pageBusyDialog = new Native.Dialog(Forms.NativeParent)
|
||||||
|
{
|
||||||
|
Orientation = PopupOrientation.Center,
|
||||||
|
BackgroundColor = EColor.Transparent
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Device.Idiom == TargetIdiom.Phone)
|
||||||
|
{
|
||||||
|
_pageBusyDialog.SetPartColor("bg_title", EColor.Transparent);
|
||||||
|
_pageBusyDialog.SetPartColor("bg_content", EColor.Transparent);
|
||||||
|
}
|
||||||
|
else if (Device.Idiom == TargetIdiom.Watch)
|
||||||
|
{
|
||||||
|
_pageBusyDialog.Style = "circle";
|
||||||
|
}
|
||||||
|
|
||||||
|
var activity = new EProgressBar(_pageBusyDialog)
|
||||||
|
{
|
||||||
|
Style = "process_large",
|
||||||
|
IsPulseMode = true,
|
||||||
|
};
|
||||||
|
activity.PlayPulse();
|
||||||
|
activity.Show();
|
||||||
|
|
||||||
|
_pageBusyDialog.Content = activity;
|
||||||
|
|
||||||
|
}
|
||||||
|
_pageBusyCount = Math.Max(0, enabled ? _pageBusyCount + 1 : _pageBusyCount - 1);
|
||||||
|
if (_pageBusyCount > 0)
|
||||||
|
{
|
||||||
|
_pageBusyDialog.Show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pageBusyDialog.Dismiss();
|
||||||
|
_pageBusyDialog = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnAlertRequest(Page sender, AlertArguments arguments)
|
||||||
|
{
|
||||||
|
// Verify that the page making the request is child of this platform
|
||||||
|
if (!_platform.PageIsChildOfPlatform(sender))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var alert = Native.Dialog.CreateDialog(Forms.NativeParent, (arguments.Accept != null));
|
||||||
|
|
||||||
|
alert.Title = arguments.Title;
|
||||||
|
var message = arguments.Message.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace(Environment.NewLine, "<br>");
|
||||||
|
alert.Message = message;
|
||||||
|
|
||||||
|
var cancel = new EButton(alert) { Text = arguments.Cancel };
|
||||||
|
alert.NegativeButton = cancel;
|
||||||
|
cancel.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
arguments.SetResult(false);
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (arguments.Accept != null)
|
||||||
|
{
|
||||||
|
var ok = new EButton(alert) { Text = arguments.Accept };
|
||||||
|
alert.NeutralButton = ok;
|
||||||
|
ok.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
arguments.SetResult(true);
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.BackButtonPressed += (s, evt) =>
|
||||||
|
{
|
||||||
|
arguments.SetResult(false);
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
alert.Show();
|
||||||
|
_alerts.Add(alert);
|
||||||
|
alert.Dismissed += (s, e) => _alerts.Remove(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnActionSheetRequest(Page sender, ActionSheetArguments arguments)
|
||||||
|
{
|
||||||
|
// Verify that the page making the request is child of this platform
|
||||||
|
if (!_platform.PageIsChildOfPlatform(sender))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var alert = Native.Dialog.CreateDialog(Forms.NativeParent);
|
||||||
|
|
||||||
|
alert.Title = arguments.Title;
|
||||||
|
var box = new Box(alert);
|
||||||
|
|
||||||
|
if (null != arguments.Destruction)
|
||||||
|
{
|
||||||
|
var destruction = new Native.Button(alert)
|
||||||
|
{
|
||||||
|
Text = arguments.Destruction,
|
||||||
|
Style = ButtonStyle.Text,
|
||||||
|
TextColor = EColor.Red,
|
||||||
|
AlignmentX = -1
|
||||||
|
};
|
||||||
|
destruction.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
arguments.SetResult(arguments.Destruction);
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
destruction.Show();
|
||||||
|
box.PackEnd(destruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string buttonName in arguments.Buttons)
|
||||||
|
{
|
||||||
|
var button = new Native.Button(alert)
|
||||||
|
{
|
||||||
|
Text = buttonName,
|
||||||
|
Style = ButtonStyle.Text,
|
||||||
|
AlignmentX = -1
|
||||||
|
};
|
||||||
|
button.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
arguments.SetResult(buttonName);
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
button.Show();
|
||||||
|
box.PackEnd(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
box.Show();
|
||||||
|
alert.Content = box;
|
||||||
|
|
||||||
|
if (null != arguments.Cancel)
|
||||||
|
{
|
||||||
|
var cancel = new EButton(Forms.NativeParent) { Text = arguments.Cancel };
|
||||||
|
alert.NegativeButton = cancel;
|
||||||
|
cancel.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.BackButtonPressed += (s, evt) =>
|
||||||
|
{
|
||||||
|
alert.Dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
alert.Show();
|
||||||
|
|
||||||
|
_alerts.Add(alert);
|
||||||
|
alert.Dismissed += (s, e) => _alerts.Remove(alert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnPromptRequested(Page sender, PromptArguments args)
|
||||||
|
{
|
||||||
|
// Verify that the page making the request is child of this platform
|
||||||
|
if (!_platform.PageIsChildOfPlatform(sender))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var prompt = Native.Dialog.CreateDialog(Forms.NativeParent, (args.Accept != null));
|
||||||
|
prompt.Title = args.Title;
|
||||||
|
|
||||||
|
var entry = new Entry
|
||||||
|
{
|
||||||
|
MinimumWidthRequest = 200,
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
BackgroundColor = Color.FromRgb(250, 250, 250),
|
||||||
|
TextColor = Color.Black,
|
||||||
|
Keyboard = args.Keyboard,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(args.Placeholder))
|
||||||
|
{
|
||||||
|
entry.Placeholder = args.Placeholder;
|
||||||
|
}
|
||||||
|
if (args.MaxLength > 0)
|
||||||
|
{
|
||||||
|
entry.MaxLength = args.MaxLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
var layout = new StackLayout
|
||||||
|
{
|
||||||
|
Spacing = 10,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new Label
|
||||||
|
{
|
||||||
|
LineBreakMode = LineBreakMode.CharacterWrap,
|
||||||
|
TextColor = Device.Idiom == TargetIdiom.Watch ? Color.White : Color.Accent,
|
||||||
|
Text = args.Message,
|
||||||
|
HorizontalOptions = LayoutOptions.FillAndExpand,
|
||||||
|
HorizontalTextAlignment = TextAlignment.Center,
|
||||||
|
FontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label)),
|
||||||
|
},
|
||||||
|
entry,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.Parent = sender;
|
||||||
|
var layoutrenderer = Platform.GetOrCreateRenderer(layout);
|
||||||
|
|
||||||
|
var request = layout.Measure(Device.Idiom == TargetIdiom.Watch ? sender.Width * 0.7 : sender.Width, sender.Height);
|
||||||
|
(layoutrenderer as LayoutRenderer).RegisterOnLayoutUpdated();
|
||||||
|
layoutrenderer.NativeView.MinimumHeight = Forms.ConvertToScaledPixel(request.Request.Height);
|
||||||
|
layoutrenderer.NativeView.MinimumWidth = Forms.ConvertToScaledPixel(request.Request.Width);
|
||||||
|
|
||||||
|
prompt.Content = layoutrenderer.NativeView;
|
||||||
|
|
||||||
|
var cancel = new EButton(prompt) { Text = args.Cancel };
|
||||||
|
prompt.NegativeButton = cancel;
|
||||||
|
cancel.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
args.SetResult(null);
|
||||||
|
prompt.Dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (args.Accept != null)
|
||||||
|
{
|
||||||
|
var ok = new EButton(prompt) { Text = args.Accept };
|
||||||
|
prompt.NeutralButton = ok;
|
||||||
|
ok.Clicked += (s, evt) =>
|
||||||
|
{
|
||||||
|
args.SetResult(entry.Text);
|
||||||
|
prompt.Dismiss();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Completed += (s, e) =>
|
||||||
|
{
|
||||||
|
args.SetResult(entry.Text);
|
||||||
|
prompt.Dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
prompt.BackButtonPressed += (s, evt) =>
|
||||||
|
{
|
||||||
|
prompt.Dismiss();
|
||||||
|
};
|
||||||
|
|
||||||
|
prompt.Show();
|
||||||
|
|
||||||
|
_alerts.Add(prompt);
|
||||||
|
prompt.Dismissed += (s, e) => _alerts.Remove(prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -177,7 +177,7 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
|
|
||||||
void UpdateAspect()
|
void UpdateAspect()
|
||||||
{
|
{
|
||||||
_image.Aspect = Element.Aspect;
|
_image.ApplyAspect(Element.Aspect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,52 +8,41 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
{
|
{
|
||||||
public class ImageRenderer : ViewRenderer<Image, Native.Image>
|
public class ImageRenderer : ViewRenderer<Image, Native.Image>
|
||||||
{
|
{
|
||||||
|
public ImageRenderer()
|
||||||
|
{
|
||||||
|
RegisterPropertyHandler(Image.SourceProperty, UpdateSource);
|
||||||
|
RegisterPropertyHandler(Image.AspectProperty, UpdateAspect);
|
||||||
|
RegisterPropertyHandler(Image.IsOpaqueProperty, UpdateIsOpaque);
|
||||||
|
RegisterPropertyHandler(Image.IsAnimationPlayingProperty, UpdateIsAnimationPlaying);
|
||||||
|
RegisterPropertyHandler(Specific.BlendColorProperty, UpdateBlendColor);
|
||||||
|
RegisterPropertyHandler(Specific.FileProperty, UpdateFile);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
|
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
|
||||||
{
|
{
|
||||||
if (Control == null)
|
if (Control == null)
|
||||||
{
|
{
|
||||||
var image = new Native.Image(Forms.NativeParent);
|
SetNativeControl(new Native.Image(Forms.NativeParent));
|
||||||
SetNativeControl(image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateAll();
|
|
||||||
base.OnElementChanged(e);
|
base.OnElementChanged(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
async void UpdateSource(bool initialize)
|
||||||
{
|
{
|
||||||
base.OnElementPropertyChanged(sender, e);
|
if (initialize && Element.Source == default(ImageSource))
|
||||||
if (e.PropertyName == Image.SourceProperty.PropertyName)
|
return;
|
||||||
{
|
|
||||||
UpdateSource();
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == Image.AspectProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateAspect();
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == Image.IsOpaqueProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateIsOpaque();
|
|
||||||
}
|
|
||||||
else if (e.PropertyName == Specific.BlendColorProperty.PropertyName)
|
|
||||||
{
|
|
||||||
UpdateBlendColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async void UpdateSource()
|
|
||||||
{
|
|
||||||
ImageSource source = Element.Source;
|
ImageSource source = Element.Source;
|
||||||
|
|
||||||
((IImageController)Element).SetIsLoading(true);
|
((IImageController)Element).SetIsLoading(true);
|
||||||
|
|
||||||
if (Control != null)
|
if (Control != null)
|
||||||
{
|
{
|
||||||
bool success = await Control.LoadFromImageSourceAsync(source);
|
bool success = await Control.LoadFromImageSourceAsync(source);
|
||||||
|
|
||||||
if (!IsDisposed && success)
|
if (!IsDisposed && success)
|
||||||
{
|
{
|
||||||
((IVisualElementController)Element).NativeSizeChanged();
|
((IVisualElementController)Element).NativeSizeChanged();
|
||||||
UpdateAfterLoading();
|
UpdateAfterLoading(initialize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,31 +50,61 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
((IImageController)Element).SetIsLoading(false);
|
((IImageController)Element).SetIsLoading(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void UpdateAfterLoading()
|
void UpdateFile(bool initialize)
|
||||||
{
|
{
|
||||||
UpdateIsOpaque();
|
if (initialize && Specific.GetFile(Element) == default || Element.Source != default(ImageSource))
|
||||||
UpdateBlendColor();
|
return;
|
||||||
|
|
||||||
|
if (Control != null)
|
||||||
|
{
|
||||||
|
bool success = Control.LoadFromFile(Specific.GetFile(Element));
|
||||||
|
|
||||||
|
if (!IsDisposed && success)
|
||||||
|
{
|
||||||
|
((IVisualElementController)Element).NativeSizeChanged();
|
||||||
|
UpdateAfterLoading(initialize);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAspect()
|
protected virtual void UpdateAfterLoading(bool initialize)
|
||||||
{
|
{
|
||||||
Control.Aspect = Element.Aspect;
|
UpdateIsOpaque(initialize);
|
||||||
|
UpdateBlendColor(initialize);
|
||||||
|
UpdateIsAnimationPlaying(initialize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateIsOpaque()
|
void UpdateAspect(bool initialize)
|
||||||
{
|
{
|
||||||
|
if (initialize && Element.Aspect == Aspect.AspectFit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Control.ApplyAspect(Element.Aspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateIsOpaque(bool initialize)
|
||||||
|
{
|
||||||
|
if (initialize && !Element.IsOpaque)
|
||||||
|
return;
|
||||||
|
|
||||||
Control.IsOpaque = Element.IsOpaque;
|
Control.IsOpaque = Element.IsOpaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateBlendColor()
|
void UpdateIsAnimationPlaying(bool initialize)
|
||||||
{
|
{
|
||||||
Control.Color = Specific.GetBlendColor(Element).ToNative();
|
if (initialize && !Element.IsAnimationPlaying)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Control.IsAnimated = Element.IsAnimationPlaying;
|
||||||
|
Control.IsAnimationPlaying = Element.IsAnimationPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateAll()
|
void UpdateBlendColor(bool initialize)
|
||||||
{
|
{
|
||||||
UpdateSource();
|
if (initialize && Specific.GetBlendColor(Element).IsDefault)
|
||||||
UpdateAspect();
|
return;
|
||||||
|
|
||||||
|
Control.Color = Specific.GetBlendColor(Element).ToNative();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using ElmSharp;
|
using ElmSharp;
|
||||||
using EColor = ElmSharp.Color;
|
|
||||||
using Xamarin.Forms.Platform.Tizen.Native;
|
using Xamarin.Forms.Platform.Tizen.Native;
|
||||||
|
using EColor = ElmSharp.Color;
|
||||||
|
using EButton = ElmSharp.Button;
|
||||||
|
using EImage = ElmSharp.Image;
|
||||||
|
|
||||||
namespace Xamarin.Forms.Platform.Tizen
|
namespace Xamarin.Forms.Platform.Tizen
|
||||||
{
|
{
|
||||||
public class ShellNavBar : Native.Box
|
public class ShellNavBar : Native.Box
|
||||||
{
|
{
|
||||||
Native.Image _menu = null;
|
EImage _menu = null;
|
||||||
|
EButton _menuButton = null;
|
||||||
Native.Label _title = null;
|
Native.Label _title = null;
|
||||||
Native.SearchBar _nativeSearchHandler = null;
|
Native.SearchBar _nativeSearchHandler = null;
|
||||||
EvasObject _nativeTitleView = null;
|
EvasObject _nativeTitleView = null;
|
||||||
ShellSectionNavigation _shellSectionNavigation = null;
|
|
||||||
|
|
||||||
SearchHandler _searchHandler = null;
|
SearchHandler _searchHandler = null;
|
||||||
View _titleView = null;
|
View _titleView = null;
|
||||||
|
@ -29,15 +31,18 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
|
|
||||||
bool _hasBackButton = false;
|
bool _hasBackButton = false;
|
||||||
|
|
||||||
public ShellNavBar(IFlyoutController flyoutController, ShellSectionNavigation shellSectionNavigation) : base(Forms.NativeParent)
|
public ShellNavBar(IFlyoutController flyoutController) : base(Forms.NativeParent)
|
||||||
{
|
{
|
||||||
_flyoutController = flyoutController;
|
_flyoutController = flyoutController;
|
||||||
_shellSectionNavigation = shellSectionNavigation;
|
|
||||||
|
|
||||||
_menu = new Native.Image(Forms.NativeParent);
|
_menuButton = new EButton(Forms.NativeParent);
|
||||||
_menu.Clicked += OnMenuClicked;
|
_menuButton.Clicked += OnMenuClicked;
|
||||||
|
_menu = new EImage(Forms.NativeParent);
|
||||||
UpdateMenuIcon();
|
UpdateMenuIcon();
|
||||||
_menu.Show();
|
_menu.Show();
|
||||||
|
_menuButton.Show();
|
||||||
|
|
||||||
|
_menuButton.SetPartContent("icon", _menu);
|
||||||
|
|
||||||
_title = new Native.Label(Forms.NativeParent)
|
_title = new Native.Label(Forms.NativeParent)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +54,8 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
_title.Show();
|
_title.Show();
|
||||||
|
|
||||||
BackgroundColor = _backgroudColor;
|
BackgroundColor = _backgroudColor;
|
||||||
PackEnd(_menu);
|
_menuButton.BackgroundColor = _backgroudColor;
|
||||||
|
PackEnd(_menuButton);
|
||||||
PackEnd(_title);
|
PackEnd(_title);
|
||||||
LayoutUpdated += OnLayoutUpdated;
|
LayoutUpdated += OnLayoutUpdated;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +129,7 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_backgroudColor = value;
|
_backgroudColor = value;
|
||||||
|
_menuButton.BackgroundColor = _backgroudColor;
|
||||||
base.BackgroundColor = _backgroudColor;
|
base.BackgroundColor = _backgroudColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +143,7 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_foregroudColor = value;
|
_foregroudColor = value;
|
||||||
_menu.Color = value;
|
_menuButton.Color = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,11 +171,11 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async void UpdateMenuIcon()
|
void UpdateMenuIcon()
|
||||||
{
|
{
|
||||||
string file = _hasBackButton ? _backIcon : _menuIcon;
|
string file = _hasBackButton ? _backIcon : _menuIcon;
|
||||||
ImageSource source = ImageSource.FromResource(file, typeof(ShellNavBar).GetTypeInfo().Assembly);
|
var path = Assembly.GetExecutingAssembly().GetManifestResourceStream(file);
|
||||||
bool ret = await _menu.LoadFromImageSourceAsync(source);
|
_menu.Load(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnMenuClicked(object sender, EventArgs e)
|
void OnMenuClicked(object sender, EventArgs e)
|
||||||
|
@ -180,7 +187,7 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
}
|
}
|
||||||
else if (_hasBackButton)
|
else if (_hasBackButton)
|
||||||
{
|
{
|
||||||
_shellSectionNavigation.PopRequest(this, new Internals.NavigationRequestedEventArgs(_page, false));
|
Shell.Current.CurrentItem.Navigation.PopAsync();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -258,8 +265,8 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
int titleLeftMargin = 40;
|
int titleLeftMargin = 40;
|
||||||
int titleViewTopMargin = 40;
|
int titleViewTopMargin = 40;
|
||||||
|
|
||||||
_menu.Move(e.Geometry.X + menuMargin, e.Geometry.Y + (e.Geometry.Height - menuSize) / 2);
|
_menuButton.Move(e.Geometry.X + menuMargin, e.Geometry.Y + (e.Geometry.Height - menuSize) / 2);
|
||||||
_menu.Resize(menuSize, menuSize);
|
_menuButton.Resize(menuSize, menuSize);
|
||||||
|
|
||||||
if (_searchHandler != null)
|
if (_searchHandler != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace Xamarin.Forms.Platform.Tizen
|
||||||
_section.PropertyChanged += OnSectionPropertyChanged;
|
_section.PropertyChanged += OnSectionPropertyChanged;
|
||||||
_rootPage = ((IShellContentController)_section.CurrentItem).GetOrCreateContent();
|
_rootPage = ((IShellContentController)_section.CurrentItem).GetOrCreateContent();
|
||||||
|
|
||||||
_navBar = new ShellNavBar(flyoutController, this);
|
_navBar = new ShellNavBar(flyoutController);
|
||||||
_navBar.Show();
|
_navBar.Show();
|
||||||
|
|
||||||
var renderer = CreateShellSection(section);
|
var renderer = CreateShellSection(section);
|
||||||
|
|
|
@ -431,7 +431,7 @@ namespace Xamarin.Forms.Platform.UWP
|
||||||
|
|
||||||
var toolBarForegroundBinder = GetToolbarProvider() as IToolBarForegroundBinder;
|
var toolBarForegroundBinder = GetToolbarProvider() as IToolBarForegroundBinder;
|
||||||
|
|
||||||
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems.OrderBy(ti => ti.Priority))
|
foreach (ToolbarItem item in _toolbarTracker.ToolbarItems)
|
||||||
{
|
{
|
||||||
toolBarForegroundBinder?.BindForegroundColor(commandBar);
|
toolBarForegroundBinder?.BindForegroundColor(commandBar);
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
{
|
{
|
||||||
int lengthDifference = base.Text.Length - Text.Length;
|
int lengthDifference = base.Text.Length - Text.Length;
|
||||||
|
|
||||||
|
var savedSelectionStart = SelectionStart;
|
||||||
string updatedRealText = DetermineTextFromPassword(Text, SelectionStart, base.Text);
|
string updatedRealText = DetermineTextFromPassword(Text, SelectionStart, base.Text);
|
||||||
|
|
||||||
if (Text == updatedRealText)
|
if (Text == updatedRealText)
|
||||||
|
@ -101,7 +102,9 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_internalChangeFlag = true;
|
||||||
Text = updatedRealText;
|
Text = updatedRealText;
|
||||||
|
_internalChangeFlag = false;
|
||||||
|
|
||||||
// Cancel any pending delayed obfuscation
|
// Cancel any pending delayed obfuscation
|
||||||
_cts?.Cancel();
|
_cts?.Cancel();
|
||||||
|
@ -118,10 +121,10 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only one character was added; we need to leave it visible for a brief time period
|
// Only one character was added; we need to leave it visible for a brief time period
|
||||||
// Obfuscate all but the last character for now
|
// Obfuscate all but the character added for now
|
||||||
newText = Obfuscate(Text, true);
|
newText = Obfuscate(Text, savedSelectionStart - 1);
|
||||||
|
|
||||||
// Leave the last character visible until a new character is added
|
// Leave the added character visible until a new character is added
|
||||||
// or sufficient time has passed
|
// or sufficient time has passed
|
||||||
if (_cts == null)
|
if (_cts == null)
|
||||||
{
|
{
|
||||||
|
@ -134,19 +137,20 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
_cts.Token.ThrowIfCancellationRequested();
|
_cts.Token.ThrowIfCancellationRequested();
|
||||||
await Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
await Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
||||||
{
|
{
|
||||||
|
var ss = SelectionStart;
|
||||||
|
var sl = SelectionLength;
|
||||||
base.Text = Obfuscate(Text);
|
base.Text = Obfuscate(Text);
|
||||||
SelectionStart = base.Text.Length;
|
SelectionStart = ss;
|
||||||
|
SelectionLength = sl;
|
||||||
}));
|
}));
|
||||||
}, _cts.Token);
|
}, _cts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base.Text == newText)
|
if (base.Text != newText)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Text = newText;
|
base.Text = newText;
|
||||||
SelectionStart = base.Text.Length;
|
}
|
||||||
|
SelectionStart = savedSelectionStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
static string DetermineTextFromPassword(string realText, int start, string passwordText)
|
static string DetermineTextFromPassword(string realText, int start, string passwordText)
|
||||||
|
@ -164,14 +168,19 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
string Obfuscate(string text, bool leaveLastVisible = false)
|
string Obfuscate(string text, int visibleSymbolIndex = -1)
|
||||||
{
|
{
|
||||||
if (!leaveLastVisible)
|
if (visibleSymbolIndex == -1)
|
||||||
return new string(ObfuscationCharacter, text?.Length ?? 0);
|
return new string(ObfuscationCharacter, text?.Length ?? 0);
|
||||||
|
|
||||||
return text == null || text.Length == 1
|
if (text == null || text.Length == 1)
|
||||||
? text
|
return text;
|
||||||
: new string(ObfuscationCharacter, text.Length - 1) + text.Substring(text.Length - 1, 1);
|
var prefix = visibleSymbolIndex > 0 ? new string(ObfuscationCharacter, visibleSymbolIndex) : string.Empty;
|
||||||
|
var suffix = visibleSymbolIndex == text.Length - 1
|
||||||
|
? string.Empty
|
||||||
|
: new string(ObfuscationCharacter, text.Length - visibleSymbolIndex - 1);
|
||||||
|
|
||||||
|
return prefix + text.Substring(visibleSymbolIndex, 1) + suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnIsPasswordChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
static void OnIsPasswordChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||||
|
@ -234,7 +243,11 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
|
|
||||||
base.OnKeyDown(e);
|
base.OnKeyDown(e);
|
||||||
if (_cachedSelectionLength > 0 && !ctrlDown)
|
if (_cachedSelectionLength > 0 && !ctrlDown)
|
||||||
|
{
|
||||||
|
var savedSelectionStart = SelectionStart;
|
||||||
Text = Text.Remove(SelectionStart, _cachedSelectionLength);
|
Text = Text.Remove(SelectionStart, _cachedSelectionLength);
|
||||||
|
SelectionStart = savedSelectionStart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -245,17 +258,7 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
{
|
{
|
||||||
if (IsPassword)
|
if (IsPassword)
|
||||||
{
|
{
|
||||||
string updatedRealText = DetermineTextFromPassword(Text, SelectionStart, base.Text);
|
DelayObfuscation();
|
||||||
string updatedText = Obfuscate(updatedRealText);
|
|
||||||
var savedSelectionStart = SelectionStart;
|
|
||||||
|
|
||||||
if (Text != updatedRealText)
|
|
||||||
Text = updatedRealText;
|
|
||||||
|
|
||||||
if (base.Text != updatedText)
|
|
||||||
base.Text = updatedText;
|
|
||||||
|
|
||||||
SelectionStart = savedSelectionStart;
|
|
||||||
}
|
}
|
||||||
else if (base.Text != Text)
|
else if (base.Text != Text)
|
||||||
{
|
{
|
||||||
|
@ -272,11 +275,11 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
{
|
{
|
||||||
if (_internalChangeFlag)
|
if (_internalChangeFlag)
|
||||||
return;
|
return;
|
||||||
|
var savedSelectionStart = SelectionStart;
|
||||||
base.Text = IsPassword ? Obfuscate(Text) : Text;
|
base.Text = IsPassword ? Obfuscate(Text) : Text;
|
||||||
DisabledText = base.Text;
|
DisabledText = base.Text;
|
||||||
|
var len = base.Text.Length;
|
||||||
SelectionStart = base.Text.Length;
|
SelectionStart = savedSelectionStart > len ? len : savedSelectionStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
static void TextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||||
|
|
|
@ -108,13 +108,17 @@ namespace Xamarin.Forms.Platform.WPF
|
||||||
((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, Control.Text);
|
((IElementController)Element).SetValueFromRenderer(Entry.TextProperty, Control.Text);
|
||||||
|
|
||||||
// If an Entry.TextChanged handler modified the value of the Entry's text, the values could now be
|
// If an Entry.TextChanged handler modified the value of the Entry's text, the values could now be
|
||||||
// out-of-sync; re-sync them and force the TextBox cursor to the end of the text
|
// out-of-sync; re-sync them and fix TextBox cursor position
|
||||||
string entryText = Element.Text;
|
string entryText = Element.Text;
|
||||||
if (Control.Text != entryText)
|
if (Control.Text != entryText)
|
||||||
{
|
{
|
||||||
Control.Text = entryText;
|
Control.Text = entryText;
|
||||||
if (Control.Text != null)
|
if (Control.Text != null)
|
||||||
Control.SelectionStart = Control.Text.Length;
|
{
|
||||||
|
var savedSelectionStart = Control.SelectionStart;
|
||||||
|
var len = Control.Text.Length;
|
||||||
|
Control.SelectionStart = savedSelectionStart > len ? len : savedSelectionStart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ignoreTextChange = false;
|
_ignoreTextChange = false;
|
||||||
|
|
|
@ -38,9 +38,7 @@ namespace Xamarin.Forms
|
||||||
static bool? s_isiOS11OrNewer;
|
static bool? s_isiOS11OrNewer;
|
||||||
static bool? s_isiOS13OrNewer;
|
static bool? s_isiOS13OrNewer;
|
||||||
static bool? s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden;
|
static bool? s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __MOBILE__
|
|
||||||
internal static bool IsiOS9OrNewer
|
internal static bool IsiOS9OrNewer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -91,6 +89,19 @@ namespace Xamarin.Forms
|
||||||
return s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden.Value;
|
return s_respondsTosetNeedsUpdateOfHomeIndicatorAutoHidden.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static bool? s_isMojaveOrNewer;
|
||||||
|
|
||||||
|
internal static bool IsMojaveOrNewer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!s_isMojaveOrNewer.HasValue)
|
||||||
|
s_isMojaveOrNewer = NSProcessInfo.ProcessInfo.IsOperatingSystemAtLeastVersion(new NSOperatingSystemVersion(10, 14, 0));
|
||||||
|
return s_isMojaveOrNewer.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static IReadOnlyList<string> s_flags;
|
static IReadOnlyList<string> s_flags;
|
||||||
|
|
|
@ -1211,7 +1211,8 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
|
|
||||||
List<UIBarButtonItem> primaries = null;
|
List<UIBarButtonItem> primaries = null;
|
||||||
List<UIBarButtonItem> secondaries = null;
|
List<UIBarButtonItem> secondaries = null;
|
||||||
foreach (var item in _tracker.ToolbarItems)
|
var toolbarItems = _tracker.ToolbarItems;
|
||||||
|
foreach (var item in toolbarItems)
|
||||||
{
|
{
|
||||||
if (item.Order == ToolbarItemOrder.Secondary)
|
if (item.Order == ToolbarItemOrder.Secondary)
|
||||||
(secondaries = secondaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(true));
|
(secondaries = secondaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(true));
|
||||||
|
|
|
@ -197,17 +197,19 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
NavigationItem.RightBarButtonItems[i].Dispose();
|
NavigationItem.RightBarButtonItems[i].Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UIBarButtonItem> items = new List<UIBarButtonItem>();
|
List<UIBarButtonItem> primaries = null;
|
||||||
if (Page != null)
|
if (Page.ToolbarItems.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var item in Page.ToolbarItems)
|
foreach (var item in System.Linq.Enumerable.OrderBy(Page.ToolbarItems, x => x.Priority))
|
||||||
{
|
{
|
||||||
items.Add(item.ToUIBarButtonItem(false, true));
|
(primaries = primaries ?? new List<UIBarButtonItem>()).Add(item.ToUIBarButtonItem(false, true));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
items.Reverse();
|
if (primaries != null)
|
||||||
NavigationItem.SetRightBarButtonItems(items.ToArray(), false);
|
primaries.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationItem.SetRightBarButtonItems(primaries == null ? new UIBarButtonItem[0] : primaries.ToArray(), false);
|
||||||
|
|
||||||
var behavior = BackButtonBehavior;
|
var behavior = BackButtonBehavior;
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,6 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
Page _displayedPage;
|
Page _displayedPage;
|
||||||
bool _disposed;
|
bool _disposed;
|
||||||
bool _firstLayoutCompleted;
|
bool _firstLayoutCompleted;
|
||||||
bool _ignorePop;
|
|
||||||
TaskCompletionSource<bool> _popCompletionTask;
|
TaskCompletionSource<bool> _popCompletionTask;
|
||||||
IShellSectionRootRenderer _renderer;
|
IShellSectionRootRenderer _renderer;
|
||||||
ShellSection _shellSection;
|
ShellSection _shellSection;
|
||||||
|
@ -73,17 +72,6 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override UIViewController PopViewController(bool animated)
|
|
||||||
{
|
|
||||||
if (!_ignorePop)
|
|
||||||
{
|
|
||||||
_popCompletionTask = new TaskCompletionSource<bool>();
|
|
||||||
SendPoppedOnCompletion(_popCompletionTask.Task);
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.PopViewController(animated);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Export("navigationBar:shouldPopItem:")]
|
[Export("navigationBar:shouldPopItem:")]
|
||||||
public bool ShouldPopItem(UINavigationBar navigationBar, UINavigationItem item)
|
public bool ShouldPopItem(UINavigationBar navigationBar, UINavigationItem item)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +84,12 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
if (allowPop)
|
if (allowPop)
|
||||||
{
|
{
|
||||||
// Do not remove, wonky behavior on some versions of iOS if you dont dispatch
|
// Do not remove, wonky behavior on some versions of iOS if you dont dispatch
|
||||||
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() => PopViewController(true));
|
CoreFoundation.DispatchQueue.MainQueue.DispatchAsync(() =>
|
||||||
|
{
|
||||||
|
_popCompletionTask = new TaskCompletionSource<bool>();
|
||||||
|
SendPoppedOnCompletion(_popCompletionTask.Task);
|
||||||
|
PopViewController(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -267,9 +260,7 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
_popCompletionTask = new TaskCompletionSource<bool>();
|
_popCompletionTask = new TaskCompletionSource<bool>();
|
||||||
e.Task = _popCompletionTask.Task;
|
e.Task = _popCompletionTask.Task;
|
||||||
|
|
||||||
_ignorePop = true;
|
|
||||||
PopViewController(animated);
|
PopViewController(animated);
|
||||||
_ignorePop = false;
|
|
||||||
|
|
||||||
await _popCompletionTask.Task;
|
await _popCompletionTask.Task;
|
||||||
|
|
||||||
|
@ -500,6 +491,20 @@ namespace Xamarin.Forms.Platform.iOS
|
||||||
navBarVisible = Shell.GetNavBarIsVisible(element);
|
navBarVisible = Shell.GetNavBarIsVisible(element);
|
||||||
|
|
||||||
navigationController.SetNavigationBarHidden(!navBarVisible, true);
|
navigationController.SetNavigationBarHidden(!navBarVisible, true);
|
||||||
|
|
||||||
|
var coordinator = viewController.GetTransitionCoordinator();
|
||||||
|
if (coordinator != null)
|
||||||
|
{
|
||||||
|
// handle swipe to dismiss gesture
|
||||||
|
coordinator.NotifyWhenInteractionEndsUsingBlock((context) =>
|
||||||
|
{
|
||||||
|
if (!context.IsCancelled)
|
||||||
|
{
|
||||||
|
_self._popCompletionTask = new TaskCompletionSource<bool>();
|
||||||
|
_self.SendPoppedOnCompletion(_self._popCompletionTask.Task);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ContentPage
|
||||||
|
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||||
|
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"
|
||||||
|
x:Class="Xamarin.Forms.Xaml.UnitTests.Gh8936"
|
||||||
|
x:DataType="local:Gh8936VM">
|
||||||
|
<Entry x:Name="entry0" Text="{Binding Data[Key]}" />
|
||||||
|
</ContentPage>
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Core.UnitTests;
|
||||||
|
|
||||||
|
namespace Xamarin.Forms.Xaml.UnitTests
|
||||||
|
{
|
||||||
|
public class Dict : Dictionary<string,string> {}
|
||||||
|
public class Gh8936VM
|
||||||
|
{
|
||||||
|
public Dict Data { get; set; } = new Dict { { "Key", "Value" } };
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class Gh8936 : ContentPage
|
||||||
|
{
|
||||||
|
public Gh8936() => InitializeComponent();
|
||||||
|
public Gh8936(bool useCompiledXaml)
|
||||||
|
{
|
||||||
|
//this stub will be replaced at compile time
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
class Tests
|
||||||
|
{
|
||||||
|
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices();
|
||||||
|
[TearDown] public void TearDown() => Device.PlatformServices = null;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void IndexerBindingOnSubclasses([Values(false, true)]bool useCompiledXaml)
|
||||||
|
{
|
||||||
|
var layout = new Gh8936(useCompiledXaml) { BindingContext = new Gh8936VM() };
|
||||||
|
Assert.That(layout.entry0.Text, Is.EqualTo("Value"));
|
||||||
|
layout.entry0.Text = "Bar";
|
||||||
|
Assert.That(layout.entry0.Text, Is.EqualTo("Bar"));
|
||||||
|
Assert.That(((Gh8936VM)layout.BindingContext).Data["Key"], Is.EqualTo("Bar"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче