diff --git a/sample/ShellExamples/FlyoutExample/App.cs b/sample/ShellExamples/FlyoutExample/App.cs
new file mode 100644
index 00000000..7c6713fa
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/App.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace FlyoutExample
+{
+ public class App : Application
+ {
+ public App()
+ {
+ MainPage = new AppShell();
+ }
+
+ protected override void OnStart()
+ {
+ // Handle when your app starts
+ }
+
+ protected override void OnSleep()
+ {
+ // Handle when your app sleeps
+ }
+
+ protected override void OnResume()
+ {
+ // Handle when your app resumes
+ }
+ }
+}
diff --git a/sample/ShellExamples/FlyoutExample/AppShell.xaml b/sample/ShellExamples/FlyoutExample/AppShell.xaml
new file mode 100644
index 00000000..26e12d7a
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/AppShell.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/FlyoutExample/AppShell.xaml.cs b/sample/ShellExamples/FlyoutExample/AppShell.xaml.cs
new file mode 100644
index 00000000..59554992
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/AppShell.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace FlyoutExample
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class AppShell : CircularShell
+ {
+ public AppShell()
+ {
+ InitializeComponent();
+ BindingContext = this;
+ }
+
+
+ public Command OnMenu1 => new Command(() =>
+ {
+ DisplayAlert("menu", "Menu1 clicked", "Ok");
+ });
+
+ public Command OnMenu2 => new Command(() =>
+ {
+ DisplayAlert("menu", "Menu2 clicked", "Ok");
+ });
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/FlyoutExample/ConfigPage.xaml b/sample/ShellExamples/FlyoutExample/ConfigPage.xaml
new file mode 100644
index 00000000..769e29ec
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/ConfigPage.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/FlyoutExample/ConfigPage.xaml.cs b/sample/ShellExamples/FlyoutExample/ConfigPage.xaml.cs
new file mode 100644
index 00000000..1b7ac162
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/ConfigPage.xaml.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace FlyoutExample
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class ConfigPage : ContentPage
+ {
+ ImageSource _imgSource1 = ImageSource.FromFile("home.png");
+ ImageSource _imgSource2 = ImageSource.FromFile("play.png");
+ public ConfigPage ()
+ {
+ InitializeComponent();
+ FlyoutSwitch.IsToggled = Shell.Current.FlyoutBehavior == FlyoutBehavior.Flyout;
+ }
+
+ void Switch_Toggled(object sender, ToggledEventArgs e)
+ {
+ Shell.Current.FlyoutBehavior = e.Value ? FlyoutBehavior.Flyout : FlyoutBehavior.Disabled;
+ }
+
+ void Button_Clicked(object sender, EventArgs e)
+ {
+ if (Shell.Current.FlyoutIcon != _imgSource1)
+ {
+ Shell.Current.FlyoutIcon = _imgSource1;
+ }
+ else
+ {
+ Shell.Current.FlyoutIcon = _imgSource2;
+ }
+ }
+
+ void Button_Clicked_1(object sender, EventArgs e)
+ {
+ Shell.Current.FlyoutIcon = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/FlyoutExample/FlyoutExample.cs b/sample/ShellExamples/FlyoutExample/FlyoutExample.cs
new file mode 100644
index 00000000..0ad640b2
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/FlyoutExample.cs
@@ -0,0 +1,23 @@
+using System;
+using Xamarin.Forms;
+
+namespace FlyoutExample
+{
+ class Program : global::Xamarin.Forms.Platform.Tizen.FormsApplication
+ {
+ protected override void OnCreate()
+ {
+ base.OnCreate();
+
+ LoadApplication(new App());
+ }
+
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ Forms.Init(app);
+ global::Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI.Init();
+ app.Run(args);
+ }
+ }
+}
diff --git a/sample/ShellExamples/FlyoutExample/FlyoutExample.csproj b/sample/ShellExamples/FlyoutExample/FlyoutExample.csproj
new file mode 100644
index 00000000..01fbd9d1
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/FlyoutExample.csproj
@@ -0,0 +1,32 @@
+
+
+
+ Exe
+ tizen40
+
+
+
+ portable
+
+
+ None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:UpdateDesignTimeXaml
+
+
+
+
diff --git a/sample/ShellExamples/FlyoutExample/FlyoutExample.sln b/sample/ShellExamples/FlyoutExample/FlyoutExample.sln
new file mode 100644
index 00000000..4c56332b
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/FlyoutExample.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.902
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlyoutExample", "FlyoutExample.csproj", "{C4EB5189-112A-4FDD-8691-C70051EEDAD7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Wearable.CircularUI.Forms", "..\..\..\src\Tizen.Wearable.CircularUI.Forms\Tizen.Wearable.CircularUI.Forms.csproj", "{FE06EF64-B2D7-4ACE-8282-C030261A3B72}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Wearable.CircularUI.Forms.Renderer", "..\..\..\src\Tizen.Wearable.CircularUI.Forms.Renderer\Tizen.Wearable.CircularUI.Forms.Renderer.csproj", "{AE954347-4639-4071-9FE1-8DBD881EE848}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C4EB5189-112A-4FDD-8691-C70051EEDAD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4EB5189-112A-4FDD-8691-C70051EEDAD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4EB5189-112A-4FDD-8691-C70051EEDAD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4EB5189-112A-4FDD-8691-C70051EEDAD7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FE06EF64-B2D7-4ACE-8282-C030261A3B72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FE06EF64-B2D7-4ACE-8282-C030261A3B72}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FE06EF64-B2D7-4ACE-8282-C030261A3B72}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FE06EF64-B2D7-4ACE-8282-C030261A3B72}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AE954347-4639-4071-9FE1-8DBD881EE848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE954347-4639-4071-9FE1-8DBD881EE848}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE954347-4639-4071-9FE1-8DBD881EE848}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE954347-4639-4071-9FE1-8DBD881EE848}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {71F3DB88-4479-4179-8FED-E60F9A0D131A}
+ EndGlobalSection
+EndGlobal
diff --git a/sample/ShellExamples/FlyoutExample/RandomColorPage.cs b/sample/ShellExamples/FlyoutExample/RandomColorPage.cs
new file mode 100644
index 00000000..2078ba30
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/RandomColorPage.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Xamarin.Forms;
+
+namespace FlyoutExample
+{
+ public class RandomColorPage : ContentPage
+ {
+ Label Title;
+ public RandomColorPage()
+ {
+ Console.WriteLine("Create RandomColorPage");
+ var rand = new Random();
+ Title = new Label()
+ {
+ HorizontalOptions = LayoutOptions.CenterAndExpand,
+ VerticalOptions = LayoutOptions.CenterAndExpand,
+ };
+ var color = Color.FromRgb(rand.Next(255), rand.Next(255), rand.Next(255));
+ Content = new StackLayout
+ {
+ HorizontalOptions = LayoutOptions.FillAndExpand,
+ VerticalOptions = LayoutOptions.FillAndExpand,
+ BackgroundColor = color,
+ Children =
+ {
+ new Label
+ {
+ HorizontalOptions = LayoutOptions.Center,
+ VerticalOptions = LayoutOptions.Center,
+ Text = $"Color : {color.ToHex()}"
+ },
+ Title,
+ }
+ };
+ }
+
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ Title.Text = Shell.Current.CurrentState.Location.ToString();
+ });
+ }
+ }
+}
diff --git a/sample/ShellExamples/FlyoutExample/SimplePage.xaml b/sample/ShellExamples/FlyoutExample/SimplePage.xaml
new file mode 100644
index 00000000..de72671d
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/SimplePage.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/FlyoutExample/SimplePage.xaml.cs b/sample/ShellExamples/FlyoutExample/SimplePage.xaml.cs
new file mode 100644
index 00000000..508d755f
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/SimplePage.xaml.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace FlyoutExample
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class SimplePage : CirclePage
+ {
+ public SimplePage()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ Title.Text = Shell.Current.CurrentState.Location.ToString();
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/FlyoutExample/res/favorite.png b/sample/ShellExamples/FlyoutExample/res/favorite.png
new file mode 100644
index 00000000..cc464d3c
Binary files /dev/null and b/sample/ShellExamples/FlyoutExample/res/favorite.png differ
diff --git a/sample/ShellExamples/FlyoutExample/res/home.png b/sample/ShellExamples/FlyoutExample/res/home.png
new file mode 100644
index 00000000..a9af000b
Binary files /dev/null and b/sample/ShellExamples/FlyoutExample/res/home.png differ
diff --git a/sample/ShellExamples/FlyoutExample/res/inbox.png b/sample/ShellExamples/FlyoutExample/res/inbox.png
new file mode 100644
index 00000000..f5df581c
Binary files /dev/null and b/sample/ShellExamples/FlyoutExample/res/inbox.png differ
diff --git a/sample/ShellExamples/FlyoutExample/res/play.png b/sample/ShellExamples/FlyoutExample/res/play.png
new file mode 100644
index 00000000..7de2079b
Binary files /dev/null and b/sample/ShellExamples/FlyoutExample/res/play.png differ
diff --git a/sample/ShellExamples/FlyoutExample/res/work.png b/sample/ShellExamples/FlyoutExample/res/work.png
new file mode 100644
index 00000000..d542624e
Binary files /dev/null and b/sample/ShellExamples/FlyoutExample/res/work.png differ
diff --git a/sample/ShellExamples/FlyoutExample/shared/res/FlyoutExample.png b/sample/ShellExamples/FlyoutExample/shared/res/FlyoutExample.png
new file mode 100644
index 00000000..9f3cb986
Binary files /dev/null and b/sample/ShellExamples/FlyoutExample/shared/res/FlyoutExample.png differ
diff --git a/sample/ShellExamples/FlyoutExample/tizen-manifest.xml b/sample/ShellExamples/FlyoutExample/tizen-manifest.xml
new file mode 100644
index 00000000..9c817e8c
--- /dev/null
+++ b/sample/ShellExamples/FlyoutExample/tizen-manifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ FlyoutExample.png
+
+
+
diff --git a/sample/ShellExamples/ShellNavigation/App.cs b/sample/ShellExamples/ShellNavigation/App.cs
new file mode 100644
index 00000000..0d8bfbf5
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/App.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace ShellNavigation
+{
+ public class App : Application
+ {
+ public App()
+ {
+ // The root page of your application
+ MainPage = new AppShell();
+
+ }
+
+ protected override void OnStart()
+ {
+ // Handle when your app starts
+ }
+
+ protected override void OnSleep()
+ {
+ // Handle when your app sleeps
+ }
+
+ protected override void OnResume()
+ {
+ // Handle when your app resumes
+ }
+ }
+}
diff --git a/sample/ShellExamples/ShellNavigation/AppShell.xaml b/sample/ShellExamples/ShellNavigation/AppShell.xaml
new file mode 100644
index 00000000..81a23668
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/AppShell.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/AppShell.xaml.cs b/sample/ShellExamples/ShellNavigation/AppShell.xaml.cs
new file mode 100644
index 00000000..4fa19aa9
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/AppShell.xaml.cs
@@ -0,0 +1,16 @@
+using Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace ShellNavigation
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class AppShell : CircularShell
+ {
+ public AppShell()
+ {
+ InitializeComponent();
+ Routing.RegisterRoute("SubPage", typeof(SubPage));
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/Main.xaml b/sample/ShellExamples/ShellNavigation/Main.xaml
new file mode 100644
index 00000000..b94a94a5
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/Main.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/Main.xaml.cs b/sample/ShellExamples/ShellNavigation/Main.xaml.cs
new file mode 100644
index 00000000..17772064
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/Main.xaml.cs
@@ -0,0 +1,34 @@
+using System;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace ShellNavigation
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class Main : ContentPage
+ {
+ public Main ()
+ {
+ InitializeComponent();
+ }
+
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ Current.Text = $"Current : {Shell.Current?.CurrentState?.Location}";
+ });
+ }
+
+ async void OnClicked(object sender, EventArgs e)
+ {
+ await Shell.Current.GoToAsync("//Setting");
+ }
+
+ async void OnClicked2(object sender, EventArgs e)
+ {
+ await Shell.Current.GoToAsync($"SubPage?from={Shell.Current.CurrentState.Location}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/Setting.xaml b/sample/ShellExamples/ShellNavigation/Setting.xaml
new file mode 100644
index 00000000..71ed3458
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/Setting.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/Setting.xaml.cs b/sample/ShellExamples/ShellNavigation/Setting.xaml.cs
new file mode 100644
index 00000000..36980571
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/Setting.xaml.cs
@@ -0,0 +1,39 @@
+using System;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace ShellNavigation
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class Setting : ContentPage
+ {
+ public Setting ()
+ {
+ InitializeComponent ();
+ }
+
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ Current.Text = $"Current : {Shell.Current?.CurrentState?.Location}";
+ });
+ }
+
+ async void OnClicked(object sender, EventArgs e)
+ {
+ await Shell.Current.GoToAsync("//Main");
+ }
+
+ async void OnClicked2(object sender, EventArgs e)
+ {
+ await Shell.Current.GoToAsync($"SubPage?from={Shell.Current.CurrentState.Location}");
+ }
+
+ async void OnClicked3(object sender, EventArgs e)
+ {
+ await Shell.Current.GoToAsync($"//Main/SubPage?from={Shell.Current.CurrentState.Location}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/ShellNavigation.cs b/sample/ShellExamples/ShellNavigation/ShellNavigation.cs
new file mode 100644
index 00000000..b0177a3e
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/ShellNavigation.cs
@@ -0,0 +1,23 @@
+using System;
+using Xamarin.Forms;
+
+namespace ShellNavigation
+{
+ class Program : global::Xamarin.Forms.Platform.Tizen.FormsApplication
+ {
+ protected override void OnCreate()
+ {
+ base.OnCreate();
+
+ LoadApplication(new App());
+ }
+
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ Forms.Init(app);
+ global::Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI.Init();
+ app.Run(args);
+ }
+ }
+}
diff --git a/sample/ShellExamples/ShellNavigation/ShellNavigation.csproj b/sample/ShellExamples/ShellNavigation/ShellNavigation.csproj
new file mode 100644
index 00000000..f4ebc26e
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/ShellNavigation.csproj
@@ -0,0 +1,30 @@
+
+
+
+ Exe
+ tizen40
+
+
+
+ portable
+
+
+ None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/ShellNavigation/ShellNavigation.sln b/sample/ShellExamples/ShellNavigation/ShellNavigation.sln
new file mode 100644
index 00000000..fcf1c586
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/ShellNavigation.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.902
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ShellNavigation", "ShellNavigation.csproj", "{5216EC27-5B70-4297-A075-178F8B19D3A3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Wearable.CircularUI.Forms", "..\..\..\src\Tizen.Wearable.CircularUI.Forms\Tizen.Wearable.CircularUI.Forms.csproj", "{8BB17722-2678-4E13-B577-650C11C3F8D9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Wearable.CircularUI.Forms.Renderer", "..\..\..\src\Tizen.Wearable.CircularUI.Forms.Renderer\Tizen.Wearable.CircularUI.Forms.Renderer.csproj", "{2838585B-8FEF-431B-BB01-185AEC8762AD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {5216EC27-5B70-4297-A075-178F8B19D3A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5216EC27-5B70-4297-A075-178F8B19D3A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5216EC27-5B70-4297-A075-178F8B19D3A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5216EC27-5B70-4297-A075-178F8B19D3A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8BB17722-2678-4E13-B577-650C11C3F8D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8BB17722-2678-4E13-B577-650C11C3F8D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8BB17722-2678-4E13-B577-650C11C3F8D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8BB17722-2678-4E13-B577-650C11C3F8D9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2838585B-8FEF-431B-BB01-185AEC8762AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2838585B-8FEF-431B-BB01-185AEC8762AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2838585B-8FEF-431B-BB01-185AEC8762AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2838585B-8FEF-431B-BB01-185AEC8762AD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {9F7C81E8-7CE6-4E7E-8D1C-21937BC7F0A8}
+ EndGlobalSection
+EndGlobal
diff --git a/sample/ShellExamples/ShellNavigation/SubPage.xaml b/sample/ShellExamples/ShellNavigation/SubPage.xaml
new file mode 100644
index 00000000..c3921a69
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/SubPage.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/SubPage.xaml.cs b/sample/ShellExamples/ShellNavigation/SubPage.xaml.cs
new file mode 100644
index 00000000..8d95069b
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/SubPage.xaml.cs
@@ -0,0 +1,55 @@
+using System;
+using Tizen.Wearable.CircularUI.Forms;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace ShellNavigation
+{
+ [QueryProperty("From", "from")]
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class SubPage : CirclePage
+ {
+ public SubPage ()
+ {
+ InitializeComponent ();
+ BindingContext = this;
+ }
+
+ string _from;
+ public string From
+ {
+ get
+ {
+ return _from;
+ }
+ set
+ {
+ _from = Uri.UnescapeDataString(value);
+ OnPropertyChanged("From");
+ }
+ }
+
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ Current.Text = $"Current : {Shell.Current?.CurrentState?.Location}";
+ });
+ }
+
+ public Command OnMain { get; } = new Command(async () =>
+ {
+ await Shell.Current.GoToAsync("//Main");
+ });
+ public Command OnSetting { get; } = new Command(async () =>
+ {
+ await Shell.Current.GoToAsync("//Setting");
+ });
+
+ async void OnClicked(object sender, EventArgs e)
+ {
+ await Shell.Current.Navigation.PopAsync();
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/ShellExamples/ShellNavigation/shared/res/ShellNavigation.png b/sample/ShellExamples/ShellNavigation/shared/res/ShellNavigation.png
new file mode 100644
index 00000000..9f3cb986
Binary files /dev/null and b/sample/ShellExamples/ShellNavigation/shared/res/ShellNavigation.png differ
diff --git a/sample/ShellExamples/ShellNavigation/tizen-manifest.xml b/sample/ShellExamples/ShellNavigation/tizen-manifest.xml
new file mode 100644
index 00000000..e291b4b3
--- /dev/null
+++ b/sample/ShellExamples/ShellNavigation/tizen-manifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ ShellNavigation.png
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Metadata.xml b/sample/ShellExamples/Xaminals/Metadata.xml
new file mode 100644
index 00000000..ae961722
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Metadata.xml
@@ -0,0 +1,11 @@
+
+
+ D8917454-5C3E-445C-BCBE-B874D0EAC0B1
+ false
+ Beginner
+ User Interface, Xamarin.Forms
+ iOS, Android
+ Indie
+ true
+ This sample demonstrates a Xamarin.Forms Shell application.
+
diff --git a/sample/ShellExamples/Xaminals/README.md b/sample/ShellExamples/Xaminals/README.md
new file mode 100644
index 00000000..972aac25
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/README.md
@@ -0,0 +1,23 @@
+---
+name: Xamarin.Forms - Xaminals
+description: "Xamarin.Forms Shell reduces the complexity of mobile application development by providing fundamental features #shell (UI)"
+page_type: sample
+languages:
+- csharp
+products:
+- xamarin
+extensions:
+ tags:
+ - ui
+ - shell
+urlFragment: userinterface-xaminals
+---
+# Xaminals
+
+Xamarin.Forms Shell reduces the complexity of mobile application development by providing the fundamental features that most mobile applications require. This includes a common navigation user experience, a URI-based navigation scheme, and an integrated search handler.
+
+This sample demonstrates a Xamarin.Forms Shell application.
+
+For more information about this sample, see [Xamarin.Forms Shell](https://docs.microsoft.com/xamarin/xamarin-forms/app-fundamentals/shell/).
+
+![Xaminals application screenshot](Screenshots/01All.png "Xaminals application screenshot")
diff --git a/sample/ShellExamples/Xaminals/Screenshots/01All.png b/sample/ShellExamples/Xaminals/Screenshots/01All.png
new file mode 100644
index 00000000..dc693f0b
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/01All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/02All.png b/sample/ShellExamples/Xaminals/Screenshots/02All.png
new file mode 100644
index 00000000..ec675fc7
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/02All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/03All.png b/sample/ShellExamples/Xaminals/Screenshots/03All.png
new file mode 100644
index 00000000..dea91c33
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/03All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/04All.png b/sample/ShellExamples/Xaminals/Screenshots/04All.png
new file mode 100644
index 00000000..7888771a
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/04All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/05All.png b/sample/ShellExamples/Xaminals/Screenshots/05All.png
new file mode 100644
index 00000000..54179fb5
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/05All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/06All.png b/sample/ShellExamples/Xaminals/Screenshots/06All.png
new file mode 100644
index 00000000..6b176b0c
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/06All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/07All.png b/sample/ShellExamples/Xaminals/Screenshots/07All.png
new file mode 100644
index 00000000..dbc82d53
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/07All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/08All.png b/sample/ShellExamples/Xaminals/Screenshots/08All.png
new file mode 100644
index 00000000..9d719663
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/08All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/09All.png b/sample/ShellExamples/Xaminals/Screenshots/09All.png
new file mode 100644
index 00000000..711c5c3b
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/09All.png differ
diff --git a/sample/ShellExamples/Xaminals/Screenshots/10All.png b/sample/ShellExamples/Xaminals/Screenshots/10All.png
new file mode 100644
index 00000000..f2323865
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Screenshots/10All.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/Xaminals.Tizen.cs b/sample/ShellExamples/Xaminals/Xaminals.Tizen/Xaminals.Tizen.cs
new file mode 100644
index 00000000..b0196ab3
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals.Tizen/Xaminals.Tizen.cs
@@ -0,0 +1,22 @@
+using System;
+using Xamarin.Forms;
+
+namespace Xaminals.Tizen
+{
+ class Program : global::Xamarin.Forms.Platform.Tizen.FormsApplication
+ {
+ protected override void OnCreate()
+ {
+ base.OnCreate();
+
+ LoadApplication(new App());
+ }
+ static void Main(string[] args)
+ {
+ var app = new Program();
+ Forms.Init(app);
+ global::Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI.Init();
+ app.Run(args);
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/Xaminals.Tizen.csproj b/sample/ShellExamples/Xaminals/Xaminals.Tizen/Xaminals.Tizen.csproj
new file mode 100644
index 00000000..53476302
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals.Tizen/Xaminals.Tizen.csproj
@@ -0,0 +1,27 @@
+
+
+
+ Exe
+ tizen40
+
+
+
+ portable
+
+
+ None
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/back.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/back.png
new file mode 100644
index 00000000..32571f18
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/back.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/bear.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/bear.png
new file mode 100644
index 00000000..5ef79e25
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/bear.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/cat.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/cat.png
new file mode 100644
index 00000000..fd5ce95f
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/cat.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/dog.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/dog.png
new file mode 100644
index 00000000..7f9b202d
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/dog.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/elephant.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/elephant.png
new file mode 100644
index 00000000..4a17db57
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/elephant.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/help.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/help.png
new file mode 100644
index 00000000..9507f758
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/help.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/info.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/info.png
new file mode 100644
index 00000000..911e745c
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/info.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/monkey.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/monkey.png
new file mode 100644
index 00000000..8b1c761b
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/monkey.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/paw.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/paw.png
new file mode 100644
index 00000000..0f8a1a9b
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/paw.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/photo.jpg b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/photo.jpg
new file mode 100644
index 00000000..07fd4b0a
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/photo.jpg differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/random.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/random.png
new file mode 100644
index 00000000..a0b40fc9
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/random.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/xamarin_logo.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/xamarin_logo.png
new file mode 100644
index 00000000..7d5007d1
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/xamarin_logo.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/xamarinstore.jpg b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/xamarinstore.jpg
new file mode 100644
index 00000000..524dff72
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/res/xamarinstore.jpg differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/shared/res/Xaminals.Tizen.png b/sample/ShellExamples/Xaminals/Xaminals.Tizen/shared/res/Xaminals.Tizen.png
new file mode 100644
index 00000000..9f3cb986
Binary files /dev/null and b/sample/ShellExamples/Xaminals/Xaminals.Tizen/shared/res/Xaminals.Tizen.png differ
diff --git a/sample/ShellExamples/Xaminals/Xaminals.Tizen/tizen-manifest.xml b/sample/ShellExamples/Xaminals/Xaminals.Tizen/tizen-manifest.xml
new file mode 100644
index 00000000..7c7905c6
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals.Tizen/tizen-manifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+ Xaminals.Tizen.png
+
+
+
+
+
+ http://tizen.org/privilege/internet
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals.sln b/sample/ShellExamples/Xaminals/Xaminals.sln
new file mode 100644
index 00000000..00ed2d82
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals.sln
@@ -0,0 +1,132 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.902
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xaminals", "Xaminals\Xaminals.csproj", "{CD4DE9E8-2721-47F3-BA95-999B6F75FF27}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xaminals.Tizen", "Xaminals.Tizen\Xaminals.Tizen.csproj", "{CC1C865A-533A-408D-B49C-974612FC515C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Wearable.CircularUI.Forms.Renderer", "..\..\..\src\Tizen.Wearable.CircularUI.Forms.Renderer\Tizen.Wearable.CircularUI.Forms.Renderer.csproj", "{ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tizen.Wearable.CircularUI.Forms", "..\..\..\src\Tizen.Wearable.CircularUI.Forms\Tizen.Wearable.CircularUI.Forms.csproj", "{50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
+ Ad-Hoc|iPhone = Ad-Hoc|iPhone
+ Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
+ AppStore|Any CPU = AppStore|Any CPU
+ AppStore|iPhone = AppStore|iPhone
+ AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
+ Debug|Any CPU = Debug|Any CPU
+ Debug|iPhone = Debug|iPhone
+ Debug|iPhoneSimulator = Debug|iPhoneSimulator
+ Release|Any CPU = Release|Any CPU
+ Release|iPhone = Release|iPhone
+ Release|iPhoneSimulator = Release|iPhoneSimulator
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.AppStore|Any CPU.Build.0 = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Release|iPhone.Build.0 = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CD4DE9E8-2721-47F3-BA95-999B6F75FF27}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Release|iPhone.Build.0 = Release|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CC1C865A-533A-408D-B49C-974612FC515C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Release|iPhone.Build.0 = Release|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {ABFA1BBA-43D8-4C1B-BADC-0A9B99A5AAD1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Release|iPhone.Build.0 = Release|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {50B3A6AD-0E0C-4845-93DB-6B6B6F8EC4D4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A341624F-77BE-4F2A-9A7A-9D34F0237697}
+ EndGlobalSection
+EndGlobal
diff --git a/sample/ShellExamples/Xaminals/Xaminals/App.xaml b/sample/ShellExamples/Xaminals/Xaminals/App.xaml
new file mode 100644
index 00000000..761ed193
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/App.xaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/Xaminals/Xaminals/App.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/App.xaml.cs
new file mode 100644
index 00000000..1df02a36
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/App.xaml.cs
@@ -0,0 +1,31 @@
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
+namespace Xaminals
+{
+ public partial class App : Application
+ {
+ public App()
+ {
+ InitializeComponent();
+
+ MainPage = new AppShell();
+ }
+
+ protected override void OnStart()
+ {
+ // Handle when your app starts
+ }
+
+ protected override void OnSleep()
+ {
+ // Handle when your app sleeps
+ }
+
+ protected override void OnResume()
+ {
+ // Handle when your app resumes
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/AppShell.xaml b/sample/ShellExamples/Xaminals/Xaminals/AppShell.xaml
new file mode 100644
index 00000000..adeb7e8e
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/AppShell.xaml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/Xaminals/Xaminals/AppShell.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/AppShell.xaml.cs
new file mode 100644
index 00000000..3c90f604
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/AppShell.xaml.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Xaminals.Views;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals
+{
+ public partial class AppShell : CircularShell
+ {
+ Random rand = new Random();
+ Dictionary routes = new Dictionary();
+ public Dictionary Routes { get { return routes; } }
+
+ public ICommand HelpCommand => new Command((url) => { }); // Device.OpenUri(new Uri(url)));
+ public ICommand RandomPageCommand => new Command(async () => await NavigateToRandomPageAsync());
+
+ public AppShell()
+ {
+ InitializeComponent();
+ RegisterRoutes();
+ BindingContext = this;
+ }
+
+ void RegisterRoutes()
+ {
+ routes.Add("monkeydetails", typeof(MonkeyDetailPage));
+ routes.Add("beardetails", typeof(BearDetailPage));
+ routes.Add("catdetails", typeof(CatDetailPage));
+ routes.Add("dogdetails", typeof(DogDetailPage));
+ routes.Add("elephantdetails", typeof(ElephantDetailPage));
+
+ foreach (var item in routes)
+ {
+ Routing.RegisterRoute(item.Key, item.Value);
+ }
+ }
+
+ async Task NavigateToRandomPageAsync()
+ {
+ string destinationRoute = routes.ElementAt(rand.Next(0, routes.Count)).Key;
+ string animalName = null;
+
+ switch (destinationRoute)
+ {
+ case "monkeydetails":
+ animalName = MonkeyData.Monkeys.ElementAt(rand.Next(0, MonkeyData.Monkeys.Count)).Name;
+ break;
+ case "beardetails":
+ animalName = BearData.Bears.ElementAt(rand.Next(0, BearData.Bears.Count)).Name;
+ break;
+ case "catdetails":
+ animalName = CatData.Cats.ElementAt(rand.Next(0, CatData.Cats.Count)).Name;
+ break;
+ case "dogdetails":
+ animalName = DogData.Dogs.ElementAt(rand.Next(0, DogData.Dogs.Count)).Name;
+ break;
+ case "elephantdetails":
+ animalName = ElephantData.Elephants.ElementAt(rand.Next(0, ElephantData.Elephants.Count)).Name;
+ break;
+ }
+
+ ShellNavigationState state = Shell.Current.CurrentState;
+ await Shell.Current.GoToAsync($"{state.Location}/{destinationRoute}?name={animalName}");
+ Shell.Current.FlyoutIsPresented = false;
+ }
+
+ void OnNavigating(object sender, ShellNavigatingEventArgs e)
+ {
+ // Cancel any back navigation
+ //if (e.Source == ShellNavigationSource.Pop)
+ //{
+ // e.Cancel();
+ //}
+ }
+
+ void OnNavigated(object sender, ShellNavigatedEventArgs e)
+ {
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Controls/AnimalSearchHandler.cs b/sample/ShellExamples/Xaminals/Xaminals/Controls/AnimalSearchHandler.cs
new file mode 100644
index 00000000..7c6dbc24
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Controls/AnimalSearchHandler.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+using Xaminals.Models;
+
+namespace Xaminals.Controls
+{
+ public class AnimalSearchHandler : SearchHandler
+ {
+ public IList Animals { get; set; }
+ public Type SelectedItemNavigationTarget { get; set; }
+
+ protected override void OnQueryChanged(string oldValue, string newValue)
+ {
+ base.OnQueryChanged(oldValue, newValue);
+
+ if (string.IsNullOrWhiteSpace(newValue))
+ {
+ ItemsSource = null;
+ }
+ else
+ {
+ ItemsSource = Animals
+ .Where(animal => animal.Name.ToLower().Contains(newValue.ToLower()))
+ .ToList();
+ }
+ }
+
+ protected override async void OnItemSelected(object item)
+ {
+ base.OnItemSelected(item);
+ await Task.Delay(1000);
+
+ ShellNavigationState state = (App.Current.MainPage as Shell).CurrentState;
+ // Note: strings will be URL encoded for navigation (e.g. "Blue Monkey" becomes "Blue%20Monkey"). Therefore, decode at the receiver.
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"{GetNavigationTarget()}?name={((Animal)item).Name}");
+ }
+
+ string GetNavigationTarget()
+ {
+ return (Shell.Current as AppShell).Routes.FirstOrDefault(route => route.Value.Equals(SelectedItemNavigationTarget)).Key;
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Controls/FlyoutHeader.xaml b/sample/ShellExamples/Xaminals/Xaminals/Controls/FlyoutHeader.xaml
new file mode 100644
index 00000000..6f0ec740
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Controls/FlyoutHeader.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Controls/FlyoutHeader.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Controls/FlyoutHeader.xaml.cs
new file mode 100644
index 00000000..0bdf5065
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Controls/FlyoutHeader.xaml.cs
@@ -0,0 +1,12 @@
+using Xamarin.Forms;
+
+namespace Xaminals.Controls
+{
+ public partial class FlyoutHeader : ContentView
+ {
+ public FlyoutHeader()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Controls/MonkeySearchHandler.cs b/sample/ShellExamples/Xaminals/Xaminals/Controls/MonkeySearchHandler.cs
new file mode 100644
index 00000000..3f64eda2
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Controls/MonkeySearchHandler.cs
@@ -0,0 +1,39 @@
+using System.Linq;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Xaminals.Models;
+
+namespace Xaminals.Controls
+{
+ public class MonkeySearchHandler : SearchHandler
+ {
+ protected override void OnQueryChanged(string oldValue, string newValue)
+ {
+ base.OnQueryChanged(oldValue, newValue);
+
+ if (string.IsNullOrWhiteSpace(newValue))
+ {
+ ItemsSource = null;
+ }
+ else
+ {
+ ItemsSource = MonkeyData.Monkeys
+ .Where(monkey => monkey.Name.ToLower().Contains(newValue.ToLower()))
+ .ToList();
+ }
+ }
+
+ protected override async void OnItemSelected(object item)
+ {
+ base.OnItemSelected(item);
+ await Task.Delay(1000);
+
+ // Note: strings will be URL encoded for navigation (e.g. "Blue Monkey" becomes "Blue%20Monkey"). Therefore, decode at the receiver.
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"monkeydetails?name={((Animal)item).Name}");
+ // The full route is shown below.
+ // await Shell.Current.GoToAsync($"//animals/monkeys/monkeydetails?name={((Animal)item).Name}");
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Data/BearData.cs b/sample/ShellExamples/Xaminals/Xaminals/Data/BearData.cs
new file mode 100644
index 00000000..0fa831d5
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Data/BearData.cs
@@ -0,0 +1,111 @@
+using System.Collections.Generic;
+using Xaminals.Models;
+
+namespace Xaminals.Data
+{
+ public static class BearData
+ {
+ public static IList Bears { get; private set; }
+
+ static BearData()
+ {
+ Bears = new List();
+
+ Bears.Add(new Animal
+ {
+ Name = "American Black Bear",
+ Location = "North America",
+ Details = "The American black bear is a medium-sized bear native to North America. It is the continent's smallest and most widely distributed bear species. American black bears are omnivores, with their diets varying greatly depending on season and location. They typically live in largely forested areas, but do leave forests in search of food. Sometimes they become attracted to human communities because of the immediate availability of food. The American black bear is the world's most common bear species.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/08/01_Schwarzbär.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Asian Black Bear",
+ Location = "Asia",
+ Details = "The Asian black bear, also known as the moon bear and the white-chested bear, is a medium-sized bear species native to Asia and largely adapted to arboreal life. It lives in the Himalayas, in the northern parts of the Indian subcontinent, Korea, northeastern China, the Russian Far East, the Honshū and Shikoku islands of Japan, and Taiwan. It is classified as vulnerable by the International Union for Conservation of Nature (IUCN), mostly because of deforestation and hunting for its body parts.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b7/Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG/180px-Ursus_thibetanus_3_%28Wroclaw_zoo%29.JPG"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Brown Bear",
+ Location = "Northern Eurasia & North America",
+ Details = "The brown bear is a bear that is found across much of northern Eurasia and North America. In North America the population of brown bears are often called grizzly bears. It is one of the largest living terrestrial members of the order Carnivora, rivaled in size only by its closest relative, the polar bear, which is much less variable in size and slightly larger on average. The brown bear's principal range includes parts of Russia, Central Asia, China, Canada, the United States, Scandinavia and the Carpathian region, especially Romania, Anatolia and the Caucasus. The brown bear is recognized as a national and state animal in several European countries.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Kamchatka_Brown_Bear_near_Dvuhyurtochnoe_on_2015-07-23.jpg/320px-Kamchatka_Brown_Bear_near_Dvuhyurtochnoe_on_2015-07-23.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Giant Panda",
+ Location = "China",
+ Details = "The giant panda, also known as panda bear or simply panda, is a bear native to south central China. It is easily recognized by the large, distinctive black patches around its eyes, over the ears, and across its round body. The name giant panda is sometimes used to distinguish it from the unrelated red panda. Though it belongs to the order Carnivora, the giant panda's diet is over 99% bamboo. Giant pandas in the wild will occasionally eat other grasses, wild tubers, or even meat in the form of birds, rodents, or carrion. In captivity, they may receive honey, eggs, fish, yams, shrub leaves, oranges, or bananas along with specially prepared food.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0f/Grosser_Panda.JPG/320px-Grosser_Panda.JPG"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Grizzly-Polar Bear Hybrid",
+ Location = "Canadian Artic",
+ Details = "A grizzly–polar bear hybrid is a rare ursid hybrid that has occurred both in captivity and in the wild. In 2006, the occurrence of this hybrid in nature was confirmed by testing the DNA of a unique-looking bear that had been shot near Sachs Harbour, Northwest Territories on Banks Island in the Canadian Arctic. The number of confirmed hybrids has since risen to eight, all of them descending from the same female polar bear.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7e/Grolar.JPG/276px-Grolar.JPG"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Sloth Bear",
+ Location = "Indian Subcontinent",
+ Details = "The sloth bear is an insectivorous bear species native to the Indian subcontinent. It is listed as Vulnerable on the IUCN Red List, mainly because of habitat loss and degradation. It has also been called labiated bear because of its long lower lip and palate used for sucking insects. Compared to brown and black bears, the sloth bear is lankier, has a long, shaggy fur and a mane around the face, and long, sickle-shaped claws. It evolved from the ancestral brown bear during the Pleistocene and through convergent evolution shares features found in insect-eating mammals.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Sloth_Bear_Washington_DC.JPG/320px-Sloth_Bear_Washington_DC.JPG"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Sun Bear",
+ Location = "Southeast Asia",
+ Details = "The sun bear is a bear species occurring in tropical forest habitats of Southeast Asia. It is listed as Vulnerable on the IUCN Red List. The global population is thought to have declined by more than 30% over the past three bear generations. Suitable habitat has been dramatically reduced due to the large-scale deforestation that has occurred throughout Southeast Asia over the past three decades. The sun bear is also known as the honey bear, which refers to its voracious appetite for honeycombs and honey.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Sitting_sun_bear.jpg/319px-Sitting_sun_bear.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Polar Bear",
+ Location = "Artic Circle",
+ Details = "The polar bear is a hypercarnivorous bear whose native range lies largely within the Arctic Circle, encompassing the Arctic Ocean, its surrounding seas and surrounding land masses. It is a large bear, approximately the same size as the omnivorous Kodiak bear. A boar (adult male) weighs around 350–700 kg (772–1,543 lb), while a sow (adult female) is about half that size. Although it is the sister species of the brown bear, it has evolved to occupy a narrower ecological niche, with many body characteristics adapted for cold temperatures, for moving across snow, ice and open water, and for hunting seals, which make up most of its diet. Although most polar bears are born on land, they spend most of their time on the sea ice. Their scientific name means maritime bear and derives from this fact. Polar bears hunt their preferred food of seals from the edge of sea ice, often living off fat reserves when no sea ice is present. Because of their dependence on the sea ice, polar bears are classified as marine mammals.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/6/66/Polar_Bear_-_Alaska_%28cropped%29.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Spectacled Bear",
+ Location = "South America",
+ Details = "The spectacled bear, also known as the Andean bear or Andean short-faced bear and locally as jukumari (Aymara), ukumari (Quechua) or ukuku, is the last remaining short-faced bear. Its closest relatives are the extinct Florida spectacled bear, and the giant short-faced bears of the Middle to Late Pleistocene age. Spectacled bears are the only surviving species of bear native to South America, and the only surviving member of the subfamily Tremarctinae. The species is classified as Vulnerable by the IUCN because of habitat loss.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/Spectacled_Bear_-_Houston_Zoo.jpg/264px-Spectacled_Bear_-_Houston_Zoo.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Cave Bear",
+ Location = "Extinct",
+ Details = "The cave bear was a species of bear that lived in Europe and Asia during the Pleistocene and became extinct about 24,000 years ago during the Last Glacial Maximum. Both the word cave and the scientific name spelaeus are used because fossils of this species were mostly found in caves. This reflects the views of experts that cave bears may have spent more time in caves than the brown bear, which uses caves only for hibernation.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Teufelshöhle-Höhlenbär-Dreiviertelprofil.jpg/320px-Teufelshöhle-Höhlenbär-Dreiviertelprofil.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "Short-faced Bear",
+ Location = "Extinct",
+ Details = "The short-faced bears is an extinct bear genus that inhabited North America during the Pleistocene epoch from about 1.8 Mya until 11,000 years ago. It was the most common early North American bear and was most abundant in California. There are two recognized species: Arctodus pristinus and Arctodus simus, with the latter considered to be one of the largest known terrestrial mammalian carnivores that has ever existed. It has been hypothesized that their extinction coincides with the Younger Dryas period of global cooling commencing around 10,900 BC.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/ArctodusSimusSkeleton.jpg/320px-ArctodusSimusSkeleton.jpg"
+ });
+
+ Bears.Add(new Animal
+ {
+ Name = "California Grizzly Bear",
+ Location = "Extinct",
+ Details = "The California grizzly bear is an extinct subspecies of the grizzly bear, the very large North American brown bear. Grizzly could have meant grizzled (that is, with golden and grey tips of the hair) or fear-inspiring. Nonetheless, after careful study, naturalist George Ord formally classified it in 1815 – not for its hair, but for its character – as Ursus horribilis (terrifying bear). Genetically, North American grizzlies are closely related; in size and coloring, the California grizzly bear was much like the grizzly bear of the southern coast of Alaska. In California, it was particularly admired for its beauty, size and strength. The grizzly became a symbol of the Bear Flag Republic, a moniker that was attached to the short-lived attempt by a group of American settlers to break away from Mexico in 1846. Later, this rebel flag became the basis for the state flag of California, and then California was known as the Bear State.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/d/de/Monarch_the_bear.jpg"
+ });
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Data/CatData.cs b/sample/ShellExamples/Xaminals/Xaminals/Data/CatData.cs
new file mode 100644
index 00000000..c30b3557
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Data/CatData.cs
@@ -0,0 +1,103 @@
+using System.Collections.Generic;
+using Xaminals.Models;
+
+namespace Xaminals.Data
+{
+ public static class CatData
+ {
+ public static IList Cats { get; private set; }
+
+ static CatData()
+ {
+ Cats = new List();
+
+ Cats.Add(new Animal
+ {
+ Name = "Abyssinian",
+ Location = "Ethopia",
+ Details = "The Abyssinian is a breed of domestic short-haired cat with a distinctive tickedtabby coat, in which individual hairs are banded with different colors. The breed is named for Abyssinia (now called Ethiopia), where it is believed to have originated.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Gustav_chocolate.jpg/168px-Gustav_chocolate.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Arabian Mau",
+ Location = "Arabian Peninsula",
+ Details = "The Arabian Mau is a formal breed of domestic cat, originated from the desert cat, a short-haired landrace native to the desert of the Arabian Peninsula. It lives there in the streets and has adapted very well to the extreme climate. The Arabian Mau is recognized as a formal breed by few fancier and breeder organization and cat registry, World Cat Federation (WCF) and Emirates Feline Federation (EFF). Based on one landrace, the Arabian Mau is a natural breed.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/d/d3/Bex_Arabian_Mau.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Bengal",
+ Location = "Asia",
+ Details = "The Bengal cat is a domesticated cat breed created from hybrids of domestic cats and the Asian leopard cat – the breed name comes from the taxonomic name. Back-crossing to domestic cats is then done with the goal of creating a healthy, and docile cat with wild-looking, high-contrast coat. Bengals have a wild appearance and may show spots, rosettes, arrowhead markings, or marbling.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Paintedcats_Red_Star_standing.jpg/187px-Paintedcats_Red_Star_standing.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Burmese",
+ Location = "Thailand",
+ Details = "The Burmese cat is a breed of domestic cat, originating in Thailand, believed to have its roots near the present Thai-Burma border and developed in the United States and Britain.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/0/04/Blissandlucky11.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Cyprus",
+ Location = "Cyprus",
+ Details = "Cyprus cats, also known as Cypriot cats, Saint Helen cats, and Saint Nicholas cats, are a landrace of domestic cat found across the island of Cyprus. A standardized breed is being developed from them; among cat fancier and breeder organizations, it is presently fully recognized by the World Cat Federation (WCF), with breeding regulated by the World Cat Congress (WCC), under the name Aphrodite's Giant; and provisionally by The International Cat Association (TICA) as the Aphrodite. All three organizations permit shorthaired and semi-longhaired versions and no out-crossing to other breeds.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b9/CyprusShorthair.jpg/320px-CyprusShorthair.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "German Rex",
+ Location = "Germany",
+ Details = "The German Rex is a medium-sized breed with slender legs of a medium length. The head is round with well-developed cheeks and large, open ears. The eyes are of medium size in colours related to the coat colour. The coat is silky and short with a tendency to curl. The whiskers also curl, though less strongly than in the Cornish Rex. They may be nearly straight. All colours of coat, including white, are allowed. The body development is heavier than in the Cornish Rex - more like the European Shorthairs.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/c/c7/German_rex_harry_%28cropped%29.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Highlander",
+ Location = "United States",
+ Details = "The Highlander (also known as the Highlander Shorthair, and originally as the Highland Lynx), is an experimental breed of cat. The unique appearance of the Highlander comes from the deliberate cross between the Desert Lynx and the Jungle Curl breeds, also recently developed. The latter of these has some non-domestic ancestry from two Asian small cat species, the leopard cat and jungle cat, making the Highlander nominally a feline hybrid, though its foundation stock is mostly domestic cat.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Highlander-7.jpg/293px-Highlander-7.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Manx",
+ Location = "Isle of Man",
+ Details = "The Manx cat is a breed of domestic cat originating on the Isle of Man, with a naturally occurring mutation that shortens the tail. Many Manx have a small stub of a tail, but Manx cats are best known as being entirely tailless; this is the most distinguishing characteristic of the breed, along with elongated hind legs and a rounded head. Manx cats come in all coat colours and patterns, though all-white specimens are rare, and the coat range of the original stock was more limited. Long-haired variants are sometimes considered a separate breed, the Cymric. Manx are prized as skilled hunters, and thus have often been sought by farmers with rodent problems, and been a preferred ship's cat breed. They are said to be social, tame and active. An old local term for the cats on their home island is stubbin. Manx have been exhibited in cat shows since the 1800s, with the first known breed standard published in 1903.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/en/9/9b/Manx_cat_by_Karen_Weaver.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Peterbald",
+ Location = "Russia",
+ Details = "The Peterbald is a cat breed of Russian origin. It was created in St Petersburg in 1994 from an experimental breeding by Olga S. Mironova. They resemble Oriental Shorthairs with a hair-losing gene. The breed was accepted for Championship class competition in 2009.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/c/c7/Peterbald_male_Shango_by_Irina_Polunina.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Scottish Fold",
+ Location = "Scotland",
+ Details = "The Scottish Fold is a breed of domestic cat with a natural dominant-gene mutation that affects cartilage throughout the body, causing the ears to fold, bending forward and down towards the front of the head, which gives the cat what is often described as an owl-like appearance.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5d/Adult_Scottish_Fold.jpg/240px-Adult_Scottish_Fold.jpg"
+ });
+
+ Cats.Add(new Animal
+ {
+ Name = "Sphynx",
+ Location = "Europe",
+ Details = "The Sphynx cat is a breed of cat known for its lack of coat (fur). It was developed through selective breeding, starting in the 1960s. The skin should have the texture of chamois, as it has fine hairs, or they may be completely hairless. Whiskers may be present, either whole or broken, or may be totally absent. They also have a narrow, long head, and webbed feet. Their skin is the color that their fur would be, and all the usual cat markings (solid, point, van, tabby, tortie, etc.) may be found on the Sphynx cat's skin. Because they have no coat, they lose more body heat than coated cats. This makes them warm to the touch as well as heat-seeking.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Sphinx2_July_2006.jpg/180px-Sphinx2_July_2006.jpg"
+ });
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Data/DogData.cs b/sample/ShellExamples/Xaminals/Xaminals/Data/DogData.cs
new file mode 100644
index 00000000..bd079e1c
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Data/DogData.cs
@@ -0,0 +1,113 @@
+using System.Collections.Generic;
+using Xaminals.Models;
+
+namespace Xaminals.Data
+{
+ public static class DogData
+ {
+ public static IList Dogs { get; private set; }
+
+ static DogData()
+ {
+ Dogs = new List();
+
+ Dogs.Add(new Animal
+ {
+ Name = "Afghan Hound",
+ Location = "Afghanistan",
+ Details = "The Afghan Hound is a hound that is distinguished by its thick, fine, silky coat and its tail with a ring curl at the end. The breed is selectively bred for its unique features in the cold mountains of Afghanistan. Other names for this breed are Kuchi Hound, Tāzī, Balkh Hound, Baluchi Hound, Barakzai Hound, Shalgar Hound, Kabul Hound, Galanday Hound or sometimes incorrectly African Hound.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/6/69/Afghane.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Alpine Dachsbracke",
+ Location = "Austria",
+ Details = "The Alpine Dachsbracke is a small breed of dog of the scent hound type originating in Austria. The Alpine Dachsbracke was bred to track wounded deer as well as boar, hare, and fox. It is highly efficient at following a trail even after it has gone cold. The Alpine Dachsbracke is very sturdy, and Austria is said to be the country of origin.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/2/23/Alpejski_gończy_krótkonożny_g99.jpg/320px-Alpejski_gończy_krótkonożny_g99.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "American Bulldog",
+ Location = "United States",
+ Details = "The American Bulldog is a breed of utility dog descended from the Old English Bulldog.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/5/5e/American_Bulldog_600.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Bearded Collie",
+ Location = "Scotland",
+ Details = "The Bearded Collie, or Beardie, is a herding breed of dog once used primarily by Scottish shepherds, but now mostly a popular family companion. Bearded Collies have an average weight of 18–27 kilograms (40–60 lb). Males are around 51–56 centimetres (20–22 in) tall at the withers while females are around 51–53 centimetres (20–21 in) tall.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/9/9c/Bearded_Collie_600.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Boston Terrier",
+ Location = "United States",
+ Details = "The Boston Terrier is a breed of dog originating in the United States of America. This American Gentleman was accepted in 1893 by the American Kennel Club as a non-sporting breed. Color and markings are important when distinguishing this breed to the AKC standard. They should be either black, brindle or seal with white markings. Bostons are small and compact with a short tail and erect ears. The AKC says they are highly intelligent and very easily trained. They are friendly and can be stubborn at times. The average life span of a Boston is around 11 to 13 years, though some can live well into their teens.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Boston-terrier-carlos-de.JPG/320px-Boston-terrier-carlos-de.JPG"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Canadian Eskimo",
+ Location = "Canada",
+ Details = "The Canadian Eskimo Dog is an Arctic breed of working dog, which is often considered to be one of North America's oldest and rarest remaining purebred indigenous domestic canines. Other names include qimmiq or qimmit. They were brought from Siberia to North America by the Thule people 1,000 years ago, along with the Greenland Dog that is genetically identical.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/7/79/Spoonsced.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Eurohound",
+ Location = "Scandinavia",
+ Details = "A Eurohound (also known as a Eurodog or Scandinavian hound) is a type of dog bred for sled dog racing. The Eurohound is typically crossbred from the Alaskan husky group and any of a number of pointing breeds.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/9/98/Eurohound.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Irish Terrier",
+ Location = "Ireland",
+ Details = "The Irish Terrier is a dog breed from Ireland, one of many breeds of terrier. The Irish Terrier is considered one of the oldest terrier breeds. The Dublin dog show in 1873 was the first to provide a separate class for Irish Terriers. By the 1880s, Irish Terriers were the fourth most popular breed in Ireland and Britain.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/IrishTerrierSydenhamHillWoods.jpg/180px-IrishTerrierSydenhamHillWoods.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Kerry Beagle",
+ Location = "Ireland",
+ Details = "The Kerry Beagle is one of the oldest Irish hound breeds, believed to be descendant from the Old Southern Hound or the Celtic Hounds. It is the only extant scent hound breed native to Ireland.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/7/75/Kerry_Beagle_from_1915.JPG"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Norwegian Buhund",
+ Location = "Norway",
+ Details = "The Norwegian Buhund is a breed of dog of the spitz type. It is closely related to the Icelandic Sheepdog and the Jämthund. The Buhund is used as an all purpose farm and herding dog, as well as watch dog and a nanny dog.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/3/3b/Norwegian_Buhund_600.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "Patterdale Terrier",
+ Location = "England",
+ Details = "The Patterdale Terrier is a breed of dog descended from the Northern terrier breeds of the early 20th century. The origins of the breed can be traced back to the Lake District, specifically to Ullswater Hunt master Joe Bowman, an early Border Terrier breeder.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/05078045_Patterdale_Terrier.jpg/320px-05078045_Patterdale_Terrier.jpg"
+ });
+
+ Dogs.Add(new Animal
+ {
+ Name = "St. Bernard",
+ Location = "Italy, Switzerland",
+ Details = "The St. Bernard or St Bernard is a breed of very large working dog from the western Alps in Italy and Switzerland. They were originally bred for rescue by the hospice of the Great St Bernard Pass on the Italian-Swiss border. The hospice, built by and named after Italian monk Bernard of Menthon, acquired its first dogs between 1660 and 1670. The breed has become famous through tales of alpine rescues, as well as for its enormous size.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/64/Hummel_Vedor_vd_Robandahoeve.jpg/320px-Hummel_Vedor_vd_Robandahoeve.jpg"
+ });
+ }
+ }
+}
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Data/ElephantData.cs b/sample/ShellExamples/Xaminals/Xaminals/Data/ElephantData.cs
new file mode 100644
index 00000000..2fa6affc
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Data/ElephantData.cs
@@ -0,0 +1,113 @@
+using System.Collections.Generic;
+using Xaminals.Models;
+
+namespace Xaminals.Data
+{
+ public static class ElephantData
+ {
+ public static IList Elephants { get; private set; }
+
+ static ElephantData()
+ {
+ Elephants = new List();
+
+ Elephants.Add(new Animal
+ {
+ Name = "African Bush Elephant",
+ Location = "Africa",
+ Details = "The African bush elephant, also known as the African savanna elephant, is the larger of the two species of African elephants, and the largest living terrestrial animal. These elephants were previously regarded as the same species, but the African forest elephant has been reclassified as L. cyclotis.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/African_Elephant_%28Loxodonta_africana%29_bull_%2831100819046%29.jpg/320px-African_Elephant_%28Loxodonta_africana%29_bull_%2831100819046%29.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "African Forest Elephant",
+ Location = "Africa",
+ Details = "The African forest elephant is a forest-dwelling species of elephant found in the Congo Basin. It is the smallest of the three extant species of elephant, but still one of the largest living terrestrial animals. The African forest elephant and the African bush elephan were considered to be one species until genetic studies indicated that they separated an estimated 2–7 million years ago. From an estimated population size of over 2 million prior to the colonization of Africa, the population in 2015 is estimated to be about 100,000 forest elephants, mostly living in the forests of Gabon. Due to a slower birth rate, the forest elephant takes longer to recover from poaching, which caused its population to fall by 65% from 2002 to 2014.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/6/6a/African_Forest_Elephant.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Desert Elephant",
+ Location = "Africa",
+ Details = "Desert elephants, or desert-adapted elephants are not a distinct species of elephant but are African bush elephants that have made their homes in the Namib and Sahara deserts in Africa. It was believed at one time that they were a subspecies of the African bush elephant but this is no longer thought to be the case. Desert-dwelling elephants were once more widespread in Africa than they are now and are currently found only in Namibia and Mali. They tend to migrate from one waterhole to another following traditional routes which depend on the seasonal availability of food and water. They face pressure from poaching and from changes in land use by humans.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/7/77/Desert_elephants_in_the_Huab_River.jpg/320px-Desert_elephants_in_the_Huab_River.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Borneo Elephant",
+ Location = "Asia",
+ Details = "The Borneo elephant, also called the Borneo pygmy elephant, is a subspecies of Asian elephant that inhabits northeastern Borneo, in Indonesia and Malaysia. Its origin remains the subject of debate. A definitive subspecific classification as Elephas maximus borneensis awaits a detailed range-wide morphometric and genetic study. Since 1986, Elephas maximus has been listed as Endangered on the IUCN Red List as the population has declined by at least 50% over the last three generations, estimated to be 60–75 years. The species is pre-eminently threatened by habitat loss, degradation and fragmentation.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e4/Elephant_%40_kabini.jpg/180px-Elephant_%40_kabini.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Indian Elephant",
+ Location = "Asia",
+ Details = "The Indian elephant is one of three extant recognized subspecies of the Asian elephant and native to mainland Asia. Since 1986, the Asian elephant has been listed as Endangered on the IUCN Red List as the wild population has declined by at least 50% since the 1930s to 1940s, i.e. three elephant generations. The Asian elephant is threatened by habitat loss, degradation and fragmentation.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Elephas_maximus_%28Bandipur%29.jpg/320px-Elephas_maximus_%28Bandipur%29.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Sri Lankan Elephant",
+ Location = "Asia",
+ Details = "The Sri Lankan elephant is one of three recognized subspecies of the Asian elephant, and native to Sri Lanka. Since 1986, Elephas maximus has been listed as endangered by IUCN as the population has declined by at least 50% over the last three generations, estimated to be 60–75 years. The species is primarily threatened by habitat loss, degradation and fragmentation.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b1/Srilankan_tuskelephant.jpg/213px-Srilankan_tuskelephant.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Sumatran Elephant",
+ Location = "Asia",
+ Details = "The Sumatran elephant is one of three recognized subspecies of the Asian elephant, and native to the Indonesia island of Sumatra. In 2011, the Sumatran elephant has been classified as critically endangered by IUCN as the population has declined by at least 80% over the last three generations, estimated to be about 75 years. The subspecies is pre-eminently threatened by habitat loss, degradation and fragmentation, and poaching; over 69% of potential elephant habitat has been lost within the last 25 years. Much of the remaining forest cover is in blocks smaller than 250 km2 (97 sq mi), which are too small to contain viable elephant populations.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Borobudur-Temple-Park_Elephant-cage-01.jpg/320px-Borobudur-Temple-Park_Elephant-cage-01.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Pygmy Elephant",
+ Location = "Africa & Asia",
+ Details = "Pygmy elephants live in both Africa and Asia.The African pygmy elephant is currently considered to be a tiny morph of the African forest elephant. The Borneo elephant, a well-documented variety of elephant, is also calledmpygmy elephant. This elephant, inhabiting tropical rainforest in north Borneo (east Sabah and extreme north Kalimantan), was long thought to be identical to the Asian elephant and descended from a captive population. In 2003, DNA comparison revealed them to be probably a new subspecies.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/9/93/Borneo-elephant-PLoS_Biology.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Mammoth",
+ Location = "Extinct",
+ Details = "A mammoth is any species of the extinct genus Mammuthus, one of the many genera that make up the order of trunked mammals called proboscideans. The various species of mammoth were commonly equipped with long, curved tusks and, in northern species, a covering of long hair. They lived from the Pliocene epoch (from around 5 million years ago) into the Holocene at about 4,000 years ago, and various species existed in Africa, Europe, Asia, and North America. They were members of the family Elephantidae, which also contains the two genera of modern elephants and their ancestors.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/Columbian_mammoth.JPG/320px-Columbian_mammoth.JPG"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Mastodon",
+ Location = "Extinct",
+ Details = "Mastodons are any species of extinct proboscideans in the genus Mammut, distantly related to elephants, that inhabited North and Central America during the late Miocene or late Pliocene up to their extinction at the end of the Pleistocene 10,000 to 11,000 years ago. Mastodons lived in herds and were predominantly forest-dwelling animals that fed on a mixed diet obtained by browsing and grazing with a seasonal preference for browsing, similar to living elephants.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Mammut_americanum.jpg/320px-Mammut_americanum.jpg"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Dwarf Elephant",
+ Location = "Extinct",
+ Details = "Dwarf elephants are prehistoric members of the order Proboscidea which, through the process of allopatric speciation on islands, evolved much smaller body sizes (around 1.5-2.3 metres) in comparison with their immediate ancestors. Dwarf elephants are an example of insular dwarfism, the phenomenon whereby large terrestrial vertebrates (usually mammals) that colonize islands evolve dwarf forms, a phenomenon attributed to adaptation to resource-poor environments and selection for early maturation and reproduction. Some modern populations of Asian elephants have also undergone size reduction on islands to a lesser degree, resulting in populations of pygmy elephants.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Elephas_skeleton.JPG/320px-Elephas_skeleton.JPG"
+ });
+
+ Elephants.Add(new Animal
+ {
+ Name = "Pygmy Mammoth",
+ Location = "Extinct",
+ Details = "The pygmy mammoth or Channel Islands mammoth is an extinct species of dwarf elephant descended from the Columbian mammoth of mainland North America. This species became extinct during the Quaternary extinction event in which many megafauna species became extinct due to changing conditions to which the species could not adapt. A case of island or insular dwarfism, from a recent analysis in 2010 it was determined that M. exilis was on average, 1.72 m (5.6 ft) tall at the shoulders and 760 kg (1,680 lb) in weight, in stark contrast to its 4.3 m (14 ft) tall, 9,070 kg (20,000 lb) ancestor. Another estimate gives a shoulder height of 2.02 m (6.6 ft) and a weight of 1,350 kg (2,980 lb).",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/f/f6/Mammuthus_exilis.jpg"
+ });
+ }
+ }
+}
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Data/MonkeyData.cs b/sample/ShellExamples/Xaminals/Xaminals/Data/MonkeyData.cs
new file mode 100644
index 00000000..5b87c2db
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Data/MonkeyData.cs
@@ -0,0 +1,151 @@
+using System.Collections.Generic;
+using Xaminals.Models;
+
+namespace Xaminals.Data
+{
+ public static class MonkeyData
+ {
+ public static IList Monkeys { get; private set; }
+
+ static MonkeyData()
+ {
+ Monkeys = new List();
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Baboon",
+ Location = "Africa & Asia",
+ Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Capuchin Monkey",
+ Location = "Central & South America",
+ Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Blue Monkey",
+ Location = "Central and East Africa",
+ Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Squirrel Monkey",
+ Location = "Central & South America",
+ Details = "The squirrel monkeys are the New World monkeys of the genus Saimiri. They are the only genus in the subfamily Saimirinae. The name of the genus Saimiri is of Tupi origin, and was also used as an English name by early researchers.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Saimiri_sciureus-1_Luc_Viatour.jpg/220px-Saimiri_sciureus-1_Luc_Viatour.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Golden Lion Tamarin",
+ Location = "Brazil",
+ Details = "The golden lion tamarin also known as the golden marmoset, is a small New World monkey of the family Callitrichidae.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/87/Golden_lion_tamarin_portrait3.jpg/220px-Golden_lion_tamarin_portrait3.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Howler Monkey",
+ Location = "South America",
+ Details = "Howler monkeys are among the largest of the New World monkeys. Fifteen species are currently recognised. Previously classified in the family Cebidae, they are now placed in the family Atelidae.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/Alouatta_guariba.jpg/200px-Alouatta_guariba.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Japanese Macaque",
+ Location = "Japan",
+ Details = "The Japanese macaque, is a terrestrial Old World monkey species native to Japan. They are also sometimes known as the snow monkey because they live in areas where snow covers the ground for months each",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Macaca_fuscata_fuscata1.jpg/220px-Macaca_fuscata_fuscata1.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Mandrill",
+ Location = "Southern Cameroon, Gabon, Equatorial Guinea, and Congo",
+ Details = "The mandrill is a primate of the Old World monkey family, closely related to the baboons and even more closely to the drill. It is found in southern Cameroon, Gabon, Equatorial Guinea, and Congo.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/7/75/Mandrill_at_san_francisco_zoo.jpg/220px-Mandrill_at_san_francisco_zoo.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Proboscis Monkey",
+ Location = "Borneo",
+ Details = "The proboscis monkey or long-nosed monkey, known as the bekantan in Malay, is a reddish-brown arboreal Old World monkey that is endemic to the south-east Asian island of Borneo.",
+ ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Proboscis_Monkey_in_Borneo.jpg/250px-Proboscis_Monkey_in_Borneo.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Red-shanked Douc",
+ Location = "Vietnam, Laos",
+ Details = "The red-shanked douc is a species of Old World monkey, among the most colourful of all primates. This monkey is sometimes called the \"costumed ape\" for its extravagant appearance. From its knees to its ankles it sports maroon-red \"stockings\", and it appears to wear white forearm length gloves. Its attire is finished with black hands and feet. The golden face is framed by a white ruff, which is considerably fluffier in males. The eyelids are a soft powder blue. The tail is white with a triangle of white hair at the base. Males of all ages have a white spot on both sides of the corners of the rump patch, and red and white genitals.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Portrait_of_a_Douc.jpg/159px-Portrait_of_a_Douc.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Gray-shanked Douc",
+ Location = "Vietnam",
+ Details = "The gray-shanked douc langur is a douc species native to the Vietnamese provinces of Quảng Nam, Quảng Ngãi, Bình Định, Kon Tum, and Gia Lai. The total population is estimated at 550 to 700 individuals. In 2016, Dr Benjamin Rawson, Country Director of Fauna & Flora International - Vietnam Programme, announced a discovery of an additional population of more than 500 individuals found in Central Vietnam, bringing the total population up to approximately 1000 individuals.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Cuc.Phuong.Primate.Rehab.center.jpg/320px-Cuc.Phuong.Primate.Rehab.center.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Golden Snub-nosed Monkey",
+ Location = "China",
+ Details = "The golden snub-nosed monkey is an Old World monkey in the Colobinae subfamily. It is endemic to a small area in temperate, mountainous forests of central and Southwest China. They inhabit these mountainous forests of Southwestern China at elevations of 1,500-3,400 m above sea level. The Chinese name is Sichuan golden hair monkey. It is also widely referred to as the Sichuan snub-nosed monkey. Of the three species of snub-nosed monkeys in China, the golden snub-nosed monkey is the most widely distributed throughout China.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Golden_Snub-nosed_Monkeys%2C_Qinling_Mountains_-_China.jpg/165px-Golden_Snub-nosed_Monkeys%2C_Qinling_Mountains_-_China.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Black Snub-nosed Monkey",
+ Location = "China",
+ Details = "The black snub-nosed monkey, also known as the Yunnan snub-nosed monkey, is an endangered species of primate in the family Cercopithecidae. It is endemic to China, where it is known to the locals as the Yunnan golden hair monkey and the black golden hair monkey. It is threatened by habitat loss. It was named after Bishop Félix Biet.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/RhinopitecusBieti.jpg/320px-RhinopitecusBieti.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Tonkin Snub-nosed Monkey",
+ Location = "Vietnam",
+ Details = "The Tonkin snub-nosed monkey or Dollman's snub-nosed monkey is a slender-bodied arboreal Old World monkey, endemic to northern Vietnam. It is a black and white monkey with a pink nose and lips and blue patches round the eyes. It is found at altitudes of 200 to 1,200 m (700 to 3,900 ft) on fragmentary patches of forest on craggy limestone areas. First described in 1912, the monkey was rediscovered in 1990 but is exceedingly rare. In 2008, fewer than 250 individuals were thought to exist, and the species was the subject of intense conservation effort. The main threats faced by these monkeys is habitat loss and hunting, and the International Union for Conservation of Nature has rated the species as \"critically endangered\".",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Tonkin_snub-nosed_monkeys_%28Rhinopithecus_avunculus%29.jpg/320px-Tonkin_snub-nosed_monkeys_%28Rhinopithecus_avunculus%29.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Thomas's Langur",
+ Location = "Indonesia",
+ Details = "Thomas's langur is a species of primate in the family Cercopithecidae. It is endemic to North Sumatra, Indonesia. Its natural habitat is subtropical or tropical dry forests. It is threatened by habitat loss. Its native names are reungkah in Acehnese and kedih in Alas.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/31/Thomas%27s_langur_Presbytis_thomasi.jpg/142px-Thomas%27s_langur_Presbytis_thomasi.jpg"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Purple-faced Langur",
+ Location = "Sri Lanka",
+ Details = "The purple-faced langur, also known as the purple-faced leaf monkey, is a species of Old World monkey that is endemic to Sri Lanka. The animal is a long-tailed arboreal species, identified by a mostly brown appearance, dark face (with paler lower face) and a very shy nature. The species was once highly prevalent, found in suburban Colombo and the \"wet zone\" villages (areas with high temperatures and high humidity throughout the year, whilst rain deluges occur during the monsoon seasons), but rapid urbanization has led to a significant decrease in the population level of the monkeys.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/Semnopithèque_blanchâtre_mâle.JPG/192px-Semnopithèque_blanchâtre_mâle.JPG"
+ });
+
+ Monkeys.Add(new Animal
+ {
+ Name = "Gelada",
+ Location = "Ethiopia",
+ Details = "The gelada, sometimes called the bleeding-heart monkey or the gelada baboon, is a species of Old World monkey found only in the Ethiopian Highlands, with large populations in the Semien Mountains. Theropithecus is derived from the Greek root words for \"beast-ape.\" Like its close relatives the baboons, it is largely terrestrial, spending much of its time foraging in grasslands.",
+ ImageUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/13/Gelada-Pavian.jpg/320px-Gelada-Pavian.jpg"
+ });
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Models/Animal.cs b/sample/ShellExamples/Xaminals/Xaminals/Models/Animal.cs
new file mode 100644
index 00000000..f61807e9
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Models/Animal.cs
@@ -0,0 +1,10 @@
+namespace Xaminals.Models
+{
+ public class Animal
+ {
+ public string Name { get; set; }
+ public string Location { get; set; }
+ public string Details { get; set; }
+ public string ImageUrl { get; set; }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/ViewModels/BearsViewModel.cs b/sample/ShellExamples/Xaminals/Xaminals/ViewModels/BearsViewModel.cs
new file mode 100644
index 00000000..559c9024
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/ViewModels/BearsViewModel.cs
@@ -0,0 +1,32 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows.Input;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Xaminals.Models;
+
+namespace Xaminals.ViewModels
+{
+ public class BearsViewModel
+ {
+ public ObservableCollection SearchResults { get; private set; }
+
+ public ICommand SearchCommand => new Command(SearchItems);
+
+ void SearchItems(string query)
+ {
+ if (string.IsNullOrWhiteSpace(query))
+ {
+ SearchResults = null;
+ }
+ else
+ {
+ var filteredItems = BearData.Bears
+ .Where(bear => bear.Name.ToLower()
+ .Contains(query.ToLower()))
+ .ToList();
+ SearchResults = new ObservableCollection(filteredItems);
+ }
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/ViewModels/MonkeyDetailViewModel.cs b/sample/ShellExamples/Xaminals/Xaminals/ViewModels/MonkeyDetailViewModel.cs
new file mode 100644
index 00000000..2d17206c
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/ViewModels/MonkeyDetailViewModel.cs
@@ -0,0 +1,50 @@
+using System;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Xaminals.Models;
+
+namespace Xaminals.ViewModels
+{
+ [QueryProperty("MonkeyName", "name")]
+ public class MonkeyDetailViewModel : INotifyPropertyChanged
+ {
+ public string MonkeyName
+ {
+ set
+ {
+ Animal monkey = MonkeyData.Monkeys.FirstOrDefault(m => m.Name == Uri.UnescapeDataString(value));
+
+ if (monkey != null)
+ {
+ Name = monkey.Name;
+ Location = monkey.Location;
+ Details = monkey.Details;
+ ImageUrl = monkey.ImageUrl;
+ OnPropertyChanged("Name");
+ OnPropertyChanged("Location");
+ OnPropertyChanged("Details");
+ OnPropertyChanged("ImageUrl");
+ }
+ }
+ }
+
+ public string Name { get; set; }
+ public string Location { get; private set; }
+ public string Details { get; private set; }
+ public string ImageUrl { get; private set; }
+
+ #region INotifyPropertyChanged
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ #endregion
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/AboutPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/AboutPage.xaml
new file mode 100644
index 00000000..40c417f6
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/AboutPage.xaml
@@ -0,0 +1,85 @@
+
+
+
+ #96d1ff
+ #999999
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/AboutPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/AboutPage.xaml.cs
new file mode 100644
index 00000000..aa39db89
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/AboutPage.xaml.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Windows.Input;
+using Xamarin.Forms;
+using Tizen.Wearable.CircularUI.Forms;
+namespace Xaminals.Views
+{
+ public partial class AboutPage : CirclePage
+ {
+ public ICommand TapCommand => new Command((url) => { /*Device.OpenUri(new Uri(url))*/});
+
+ public AboutPage()
+ {
+ InitializeComponent();
+ BindingContext = this;
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/BearDetailPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/BearDetailPage.xaml
new file mode 100644
index 00000000..e45f60b3
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/BearDetailPage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/BearDetailPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/BearDetailPage.xaml.cs
new file mode 100644
index 00000000..1f5668ea
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/BearDetailPage.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ [QueryProperty("Name", "name")]
+ public partial class BearDetailPage : CirclePage
+ {
+ public string Name
+ {
+ set
+ {
+ BindingContext = BearData.Bears.FirstOrDefault(m => m.Name == Uri.UnescapeDataString(value));
+ }
+ }
+
+ public BearDetailPage()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/BearsPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/BearsPage.xaml
new file mode 100644
index 00000000..ab964ec2
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/BearsPage.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/BearsPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/BearsPage.xaml.cs
new file mode 100644
index 00000000..659e630c
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/BearsPage.xaml.cs
@@ -0,0 +1,25 @@
+using Xamarin.Forms;
+using Xaminals.Models;
+using Xaminals.ViewModels;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ public partial class BearsPage : CirclePage
+ {
+ public BearsPage()
+ {
+ InitializeComponent();
+ BindingContext = new BearsViewModel();
+ }
+
+ async void OnItemSelected(object sender, ItemTappedEventArgs e)
+ {
+ string bearName = (e.Item as Animal).Name;
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"beardetails?name={bearName}");
+ // The full route is shown below.
+ // await Shell.Current.GoToAsync($"//animals/bears/beardetails?name={bearName}");
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/CatDetailPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/CatDetailPage.xaml
new file mode 100644
index 00000000..46eebd88
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/CatDetailPage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/CatDetailPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/CatDetailPage.xaml.cs
new file mode 100644
index 00000000..163ed9a0
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/CatDetailPage.xaml.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ [QueryProperty("Name", "name")]
+ public partial class CatDetailPage : CirclePage
+ {
+ public string Name
+ {
+ set
+ {
+ BindingContext = CatData.Cats.FirstOrDefault(m => m.Name == Uri.UnescapeDataString(value));
+ }
+ }
+
+ public CatDetailPage()
+ {
+ InitializeComponent();
+ }
+
+ protected override bool OnBackButtonPressed()
+ {
+ return base.OnBackButtonPressed();
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/CatsPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/CatsPage.xaml
new file mode 100644
index 00000000..b0749bbe
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/CatsPage.xaml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/CatsPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/CatsPage.xaml.cs
new file mode 100644
index 00000000..0416a885
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/CatsPage.xaml.cs
@@ -0,0 +1,24 @@
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Models;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ public partial class CatsPage : CirclePage
+ {
+ public CatsPage()
+ {
+ InitializeComponent();
+ }
+
+ async void OnItemSelected(object sender, ItemTappedEventArgs e)
+ {
+ string catName = (e.Item as Animal).Name;
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"catdetails?name={catName}");
+ // The full route is shown below.
+ // await Shell.Current.GoToAsync($"//animals/domestic/cats/catdetails?name={catName}");
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/DogDetailPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/DogDetailPage.xaml
new file mode 100644
index 00000000..884e2040
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/DogDetailPage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/DogDetailPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/DogDetailPage.xaml.cs
new file mode 100644
index 00000000..573e0caa
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/DogDetailPage.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ [QueryProperty("Name", "name")]
+ public partial class DogDetailPage : CirclePage
+ {
+ public string Name
+ {
+ set
+ {
+ BindingContext = DogData.Dogs.FirstOrDefault(m => m.Name == Uri.UnescapeDataString(value));
+ }
+ }
+
+ public DogDetailPage()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/DogsPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/DogsPage.xaml
new file mode 100644
index 00000000..5d829d9a
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/DogsPage.xaml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/DogsPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/DogsPage.xaml.cs
new file mode 100644
index 00000000..cdd7d092
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/DogsPage.xaml.cs
@@ -0,0 +1,24 @@
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Models;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ public partial class DogsPage : CirclePage
+ {
+ public DogsPage()
+ {
+ InitializeComponent();
+ }
+
+ async void OnItemSelected(object sender, ItemTappedEventArgs e)
+ {
+ string dogName = (e.Item as Animal).Name;
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"dogdetails?name={dogName}");
+ // The full route is shown below.
+ // await Shell.Current.GoToAsync($"//animals/domestic/dogs/dogdetails?name={dogName}");
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantDetailPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantDetailPage.xaml
new file mode 100644
index 00000000..6c3bc8c7
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantDetailPage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantDetailPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantDetailPage.xaml.cs
new file mode 100644
index 00000000..9dcb853e
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantDetailPage.xaml.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Data;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ [QueryProperty("Name", "name")]
+ public partial class ElephantDetailPage : CirclePage
+ {
+ public string Name
+ {
+ set
+ {
+ BindingContext = ElephantData.Elephants.FirstOrDefault(m => m.Name == Uri.UnescapeDataString(value));
+ }
+ }
+
+ public ElephantDetailPage()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantsPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantsPage.xaml
new file mode 100644
index 00000000..4d84db01
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantsPage.xaml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantsPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantsPage.xaml.cs
new file mode 100644
index 00000000..71435cab
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/ElephantsPage.xaml.cs
@@ -0,0 +1,24 @@
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Models;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ public partial class ElephantsPage : CirclePage
+ {
+ public ElephantsPage()
+ {
+ InitializeComponent();
+ }
+
+ async void OnItemSelected(object sender, ItemTappedEventArgs e)
+ {
+ string elephantName = (e.Item as Animal).Name;
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"elephantdetails?name={elephantName}");
+ // The full route is shown below.
+ // await Shell.Current.GoToAsync($"//animals/elephants/elephantdetails?name={elephantName}");
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeyDetailPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeyDetailPage.xaml
new file mode 100644
index 00000000..37ae7d86
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeyDetailPage.xaml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeyDetailPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeyDetailPage.xaml.cs
new file mode 100644
index 00000000..ed81b686
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeyDetailPage.xaml.cs
@@ -0,0 +1,15 @@
+using Xamarin.Forms;
+using Xaminals.ViewModels;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ public partial class MonkeyDetailPage : CirclePage
+ {
+ public MonkeyDetailPage()
+ {
+ InitializeComponent();
+ BindingContext = new MonkeyDetailViewModel();
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeysPage.xaml b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeysPage.xaml
new file mode 100644
index 00000000..789dd189
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeysPage.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeysPage.xaml.cs b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeysPage.xaml.cs
new file mode 100644
index 00000000..ba637b6e
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Views/MonkeysPage.xaml.cs
@@ -0,0 +1,24 @@
+using System.Linq;
+using Xamarin.Forms;
+using Xaminals.Models;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Xaminals.Views
+{
+ public partial class MonkeysPage : CirclePage
+ {
+ public MonkeysPage()
+ {
+ InitializeComponent();
+ }
+
+ async void OnItemSelected(object sender, ItemTappedEventArgs e)
+ {
+ string monkeyName = (e.Item as Animal).Name;
+ // This works because route names are unique in this application.
+ await Shell.Current.GoToAsync($"monkeydetails?name={monkeyName}");
+ // The full route is shown below.
+ // await Shell.Current.GoToAsync($"//animals/monkeys/monkeydetails?name={monkeyName}");
+ }
+ }
+}
diff --git a/sample/ShellExamples/Xaminals/Xaminals/Xaminals.csproj b/sample/ShellExamples/Xaminals/Xaminals/Xaminals.csproj
new file mode 100644
index 00000000..a7571385
--- /dev/null
+++ b/sample/ShellExamples/Xaminals/Xaminals/Xaminals.csproj
@@ -0,0 +1,25 @@
+
+
+
+ netstandard2.0
+
+
+
+ pdbonly
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListView.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/CircleListView.cs
old mode 100755
new mode 100644
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs
index eb050317..a9efb6cb 100644
--- a/src/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/CirclePageRenderer.cs
@@ -59,6 +59,20 @@ public CirclePageRenderer()
public ElmSharp.Wearable.CircleSurface CircleSurface => _surface;
+ public void UpdateRotaryFocusObject(bool initialize)
+ {
+ if (initialize)
+ {
+ _currentRotaryFocusObject = Element.RotaryFocusObject;
+ }
+ else
+ {
+ DeactivateRotaryWidget();
+ _currentRotaryFocusObject = Element.RotaryFocusObject;
+ ActivateRotaryWidget();
+ }
+ }
+
protected override void OnElementChanged(ElementChangedEventArgs e)
{
if (_box == null)
@@ -96,6 +110,18 @@ protected override void OnElementChanged(ElementChangedEventArgs e)
}
base.OnElementChanged(e);
}
+
+ protected override void OnElementReady()
+ {
+ base.OnElementReady();
+ // A Page created by with ContentTemplate of ShellContent, was appered before create a renderer
+ // So need to call OnPageAppearing if page already appeared
+ if (Element.Appeared)
+ {
+ OnPageAppearing(Element, EventArgs.Empty);
+ }
+ }
+
protected override void UpdateBackgroundColor(bool initialize)
{
if (initialize && Element.BackgroundColor.IsDefault) return;
@@ -190,6 +216,7 @@ void OnRealized()
SetNativeView(_box);
}
+
void OnLayout()
{
var rect = _box.Geometry;
@@ -371,19 +398,7 @@ void OnMoreOptionClicked(object sender, ElmSharp.Wearable.MoreOptionItemEventArg
}
_moreOption.IsOpened = false;
}
- void UpdateRotaryFocusObject(bool initialize)
- {
- if (initialize)
- {
- _currentRotaryFocusObject = Element.RotaryFocusObject;
- }
- else
- {
- DeactivateRotaryWidget();
- _currentRotaryFocusObject = Element.RotaryFocusObject;
- ActivateRotaryWidget();
- }
- }
+
void OnPageDisappearing(object sender, EventArgs e)
{
DeactivateRotaryWidget();
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs
new file mode 100644
index 00000000..bdeaa595
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/IShellItemRenderer.cs
@@ -0,0 +1,12 @@
+using System;
+using ElmSharp;
+using Xamarin.Forms;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public interface IShellItemRenderer : IDisposable
+ {
+ BaseShellItem Item { get; }
+ EvasObject NativeView { get; }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs
new file mode 100644
index 00000000..7f0b0b5c
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationDrawer.cs
@@ -0,0 +1,426 @@
+using System;
+using System.Threading.Tasks;
+using System.Threading;
+using Xamarin.Forms;
+using ElmSharp;
+using ElmSharp.Wearable;
+using EWidget = ElmSharp.Widget;
+using ELayout = ElmSharp.Layout;
+using NImage = Xamarin.Forms.Platform.Tizen.Native.Image;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class NavigationDrawer : ELayout, IAnimatable
+ {
+
+ static readonly string DefaultIcon = "Tizen.Wearable.CircularUI.Forms.Renderer.res.drag_handle_white_18dp.png";
+
+ int _iconHeight = 40;
+
+ Box _mainLayout;
+ Box _contentBox;
+ Box _drawerBox;
+ Box _drawerContentBox;
+ Box _drawerIconBox;
+
+ EvasObject _content;
+ EvasObject _drawerContent;
+ NImage _drawerIcon;
+
+ GestureLayer _contentGesture;
+ GestureLayer _drawerGesture;
+
+ bool _isOpen;
+
+ CancellationTokenSource _fadeInCancelTokenSource = null;
+
+ public int IconHeight
+ {
+ get
+ {
+ return _iconHeight;
+ }
+ set
+ {
+ _iconHeight = value;
+ }
+ }
+
+ public bool IsOpen
+ {
+ get
+ {
+ return _isOpen;
+ }
+ set
+ {
+ if (_isOpen != value)
+ {
+ if (value)
+ {
+ Open();
+ }
+ else
+ {
+ Close();
+ }
+ }
+ }
+ }
+
+ public event EventHandler Toggled;
+
+ public NavigationDrawer(EvasObject parent) : base(parent)
+ {
+ Initialize();
+ }
+
+ public void SetMainContent(EvasObject content)
+ {
+ if (content == null)
+ {
+ UnsetMainContent();
+ return;
+ }
+
+ _content = content;
+ _content.Show();
+ _contentBox.PackEnd(_content);
+ _content.Geometry = _contentBox.Geometry;
+ }
+
+ public void SetDrawerContent(EvasObject content)
+ {
+ if (content == null)
+ {
+ UnsetDrawerContent();
+ return;
+ }
+
+ _drawerContent = content;
+ _drawerContent.Show();
+ _drawerContentBox.PackEnd(_drawerContent);
+
+ _drawerContentBox.Show();
+ _drawerIconBox.Show();
+
+ if (_drawerContent is NavigationView nv)
+ {
+ nv.Dragged += (s, e) =>
+ {
+ if (e.State == DraggedState.EdgeTop)
+ {
+ Close();
+ }
+ };
+ }
+ }
+
+ public void UpdateDrawerIcon(ImageSource source)
+ {
+ if (source == null)
+ {
+ _drawerIcon.LoadFromImageSourceAsync(ImageSource.FromResource(DefaultIcon, GetType().Assembly));
+ }
+ else
+ {
+ _drawerIconBox.UnPack(_drawerIcon);
+ _drawerIcon.Unrealize();
+
+ _drawerIcon = new NImage(this)
+ {
+ AlignmentY = -1,
+ AlignmentX = -1,
+ WeightX = 1,
+ WeightY = 1
+ };
+ _drawerIcon.Show();
+ _drawerIconBox.PackEnd(_drawerIcon);
+
+ if (source is FileImageSource fsource)
+ {
+ _drawerIcon.Load(fsource.ToAbsPath());
+ }
+ else
+ {
+ _drawerIcon.LoadFromImageSourceAsync(source);
+ }
+ }
+ }
+
+ public async void Open(uint length = 300)
+ {
+ var toMove = _drawerBox.Geometry;
+ toMove.Y = 0;
+
+ await RunMoveAnimation(_drawerBox, toMove, length);
+
+ if (!_isOpen)
+ {
+ _isOpen = true;
+ Toggled?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ public async void Close(uint length = 300)
+ {
+ var toMove = _drawerBox.Geometry;
+ toMove.Y = Geometry.Height - _iconHeight;
+
+ await RunMoveAnimation(_drawerBox, toMove, length);
+
+ if (_isOpen)
+ {
+ _isOpen = false;
+ Toggled?.Invoke(this, EventArgs.Empty);
+ }
+ }
+
+ protected override IntPtr CreateHandle(EvasObject parent)
+ {
+ _mainLayout = new Box(parent);
+ return _mainLayout.Handle;
+ }
+
+ void IAnimatable.BatchBegin()
+ {
+ }
+
+ void IAnimatable.BatchCommit()
+ {
+ }
+
+ void Initialize()
+ {
+ AlignmentX = -1;
+ AlignmentY = -1;
+ WeightX = 1;
+ WeightY = 1;
+
+ _contentBox = new Box(_mainLayout);
+ _contentBox.Show();
+ _mainLayout.PackEnd(_contentBox);
+
+ _drawerBox = new Box(_mainLayout);
+ _drawerBox.Show();
+ _mainLayout.PackEnd(_drawerBox);
+
+ _drawerContentBox = new Box(_drawerBox);
+ _drawerBox.PackEnd(_drawerContentBox);
+
+ _drawerIconBox = new Box(_drawerBox);
+ _drawerBox.PackEnd(_drawerIconBox);
+
+ _drawerIcon = new NImage(this)
+ {
+ AlignmentY = -1,
+ AlignmentX = -1,
+ WeightX = 1,
+ WeightY = 1
+ };
+ _drawerIcon.Show();
+ using (var stream = GetType().Assembly.GetManifestResourceStream(DefaultIcon))
+ {
+ _drawerIcon.Load(stream);
+ }
+
+ _drawerIconBox.PackEnd(_drawerIcon);
+
+ _contentGesture = new GestureLayer(_contentBox);
+ _contentGesture.Attach(_contentBox);
+ _contentGesture.SetMomentumCallback(GestureLayer.GestureState.Start, OnContentDragStarted);
+ _contentGesture.SetMomentumCallback(GestureLayer.GestureState.End, OnContentDragEnded);
+ _contentGesture.SetMomentumCallback(GestureLayer.GestureState.Abort, OnContentDragEnded);
+
+ _drawerGesture = new GestureLayer(_drawerIconBox);
+ _drawerGesture.Attach(_drawerIconBox);
+
+ _drawerGesture.SetMomentumCallback(GestureLayer.GestureState.Move, OnDrawerDragged);
+ _drawerGesture.SetMomentumCallback(GestureLayer.GestureState.End, OnDrawerDragEnded);
+ _drawerGesture.SetMomentumCallback(GestureLayer.GestureState.Abort, OnDrawerDragEnded);
+
+ _mainLayout.SetLayoutCallback(OnLayout);
+ _drawerBox.SetLayoutCallback(OnDrawerContentLayout);
+ _contentBox.SetLayoutCallback(OnContentLayout);
+
+ RotaryEventManager.Rotated += OnRotateEventReceived;
+ }
+
+ async Task ShowAsync(EWidget target, Easing easing = null, uint length = 300, CancellationToken cancelltaionToken = default(CancellationToken))
+ {
+ var tcs = new TaskCompletionSource();
+
+ await Task.Delay(1000);
+
+ if (cancelltaionToken.IsCancellationRequested)
+ {
+ cancelltaionToken.ThrowIfCancellationRequested();
+ }
+
+ target.Show();
+ var opacity = target.Opacity;
+
+ if (opacity == 255 || opacity == -1)
+ return true;
+
+ new Animation((progress) =>
+ {
+ target.Opacity = opacity + (int)((255 - opacity) * progress);
+
+ }).Commit(this, "FadeIn", length: length, finished: (p, e) =>
+ {
+ target.Opacity = 255;
+ tcs.SetResult(true);
+ });
+
+ return await tcs.Task;
+ }
+
+ void OnLayout()
+ {
+ var geometry = Geometry;
+ _contentBox.Geometry = geometry;
+
+ geometry.Y = (_isOpen) ? 0 : (geometry.Height - _iconHeight);
+ _drawerBox.Geometry = geometry;
+ }
+
+ void OnContentLayout()
+ {
+ if (_content != null)
+ {
+ _content.Geometry = _contentBox.Geometry;
+ }
+ }
+
+ void OnDrawerContentLayout()
+ {
+ var geometry = _drawerBox.Geometry;
+ _drawerContentBox.Geometry = _drawerBox.Geometry;
+
+ geometry.Height = _iconHeight;
+ _drawerIconBox.Geometry = geometry;
+
+ _drawerIconBox.StackAbove(_drawerContentBox);
+ }
+
+ async Task HideAsync(EWidget target, Easing easing = null, uint length = 300)
+ {
+ var tcs = new TaskCompletionSource();
+
+ var opacity = target.Opacity;
+ if (opacity == -1)
+ opacity = 255;
+
+ new Animation((progress) =>
+ {
+ target.Opacity = opacity - (int)(progress * opacity);
+
+ }).Commit(this, "FadeOut", length: length, finished: (p, e) =>
+ {
+ target.Opacity = 0;
+ target.Hide();
+ tcs.SetResult(true);
+ });
+
+ return await tcs.Task;
+ }
+
+ async void OnRotateEventReceived(EventArgs args)
+ {
+ _fadeInCancelTokenSource?.Cancel();
+
+ _fadeInCancelTokenSource = new CancellationTokenSource();
+ var token = _fadeInCancelTokenSource.Token;
+
+ if (!_isOpen)
+ {
+ await HideAsync(_drawerBox);
+
+ _ = ShowAsync(_drawerBox, cancelltaionToken: token);
+ }
+ }
+
+ void OnContentDragStarted(GestureLayer.MomentumData moment)
+ {
+ _fadeInCancelTokenSource?.Cancel();
+ _fadeInCancelTokenSource = null;
+
+ if (!_isOpen)
+ {
+ _ = HideAsync(_drawerBox);
+ }
+ }
+
+ void OnContentDragEnded(GestureLayer.MomentumData moment)
+ {
+ _fadeInCancelTokenSource = new CancellationTokenSource();
+
+ _ = ShowAsync(_drawerBox, cancelltaionToken: _fadeInCancelTokenSource.Token);
+ }
+
+ void OnDrawerDragged(GestureLayer.MomentumData moment)
+ {
+ var toMove = _drawerBox.Geometry;
+ toMove.Y = (moment.Y2 < 0) ? 0 : moment.Y2;
+
+ _drawerBox.Geometry = toMove;
+ }
+
+ void OnDrawerDragEnded(GestureLayer.MomentumData moment)
+ {
+ if (_drawerBox.Geometry.Y < (_mainLayout.Geometry.Height / 2))
+ {
+ Open();
+ }
+ else
+ {
+ Close();
+ }
+ }
+
+ Task RunMoveAnimation(EvasObject target, Rect dest, uint length, Easing easing = null)
+ {
+ var tcs = new TaskCompletionSource();
+
+ var dx = target.Geometry.X - dest.X;
+ var dy = target.Geometry.Y - dest.Y;
+
+ new Animation((progress) =>
+ {
+ var toMove = dest;
+ toMove.X += (int)(dx * (1 - progress));
+ toMove.Y += (int)(dy * (1 - progress));
+ target.Geometry = toMove;
+ }).Commit(this, "Move", length: length, finished: (s, e) =>
+ {
+ target.Geometry = dest;
+ tcs.SetResult(true);
+ });
+ return tcs.Task;
+ }
+
+ void UnsetMainContent()
+ {
+ if (_content != null)
+ {
+ _contentBox.UnPack(_content);
+ _content.Hide();
+ _content = null;
+ }
+ }
+
+ void UnsetDrawerContent()
+ {
+ if (_drawerContent != null)
+ {
+ _drawerContentBox.UnPack(_drawerContent);
+ _drawerContent.Hide();
+ _drawerContent = null;
+
+ _drawerContentBox.Hide();
+ _drawerIconBox.Hide();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs
new file mode 100644
index 00000000..abacdceb
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/NavigationView.cs
@@ -0,0 +1,239 @@
+using ElmSharp;
+using ElmSharp.Wearable;
+using System;
+using System.Collections.Generic;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+using ELayout = ElmSharp.Layout;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class NavigationView : ELayout
+ {
+ readonly int _dafaultIconSize = 60;
+
+ class Item
+ {
+ public Element Source { get; set; }
+ public string Text { get; set; }
+ public string Icon { get; set; }
+ }
+
+ Box _outterBox;
+ ELayout _surfaceLayout;
+ CircleSurface _surface;
+ CircleGenList _naviMenu;
+
+ GenItemClass _defaultClass;
+ SmartEvent _draggedUpCallback;
+ SmartEvent _draggedDownCallback;
+
+ GenListItem _header;
+ GenListItem _footer;
+
+ List> _itemCache;
+
+ public NavigationView(EvasObject parent) : base(parent)
+ {
+ InitializeComponent();
+ }
+
+ public event EventHandler ItemSelected;
+
+ public event EventHandler Dragged;
+
+ public void Build(List> items)
+ {
+ // Only update when items was changed
+ if (!IsUpdated(items))
+ {
+ return;
+ }
+ _itemCache = items;
+
+ _naviMenu.Clear();
+ // header
+ _header = _naviMenu.Append(_defaultClass, new Item { Text = "" });
+
+ // TODO. need to improve, need to support group
+ foreach (var group in items)
+ {
+ foreach (var item in group)
+ {
+ var data = new Item
+ {
+ Source = item
+ };
+ if (item is BaseShellItem shellItem)
+ {
+ data.Text = shellItem.Title;
+ data.Icon = (shellItem.Icon as FileImageSource)?.ToAbsPath();
+ }
+ else if (item is MenuItem menuItem)
+ {
+ data.Text = menuItem.Text;
+ data.Icon = (menuItem.IconImageSource as FileImageSource)?.ToAbsPath();
+ }
+ var genitem = _naviMenu.Append(_defaultClass, data, GenListItemType.Normal);
+ genitem.SetPartColor("bg", ElmSharp.Color.Gray);
+ }
+ }
+ _footer = _naviMenu.Append(_defaultClass, new Item { Text = "" });
+ }
+
+ public void Activate()
+ {
+ (_naviMenu as IRotaryActionWidget)?.Activate();
+ }
+ public void Deactivate()
+ {
+ (_naviMenu as IRotaryActionWidget)?.Deactivate();
+ }
+
+ protected override IntPtr CreateHandle(EvasObject parent)
+ {
+ _outterBox = new Box(parent);
+ return _outterBox.Handle;
+ }
+
+ void InitializeComponent()
+ {
+ _outterBox.SetLayoutCallback(OnLayout);
+
+ _surfaceLayout = new ELayout(this);
+ _surfaceLayout.Show();
+ _surface = new CircleSurface(_surfaceLayout);
+
+ _naviMenu = new CircleGenList(this, _surface)
+ {
+ Homogeneous = true,
+ BackgroundColor = ElmSharp.Color.Gray
+ };
+ _naviMenu.Show();
+
+ _draggedUpCallback = new SmartEvent(_naviMenu, "drag,start,up");
+ _draggedUpCallback.On += (s, e) =>
+ {
+ if (_footer.TrackObject.IsVisible)
+ {
+ Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.EdgeBottom));
+ }
+ else
+ {
+ Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.Up));
+ }
+ };
+
+ _draggedDownCallback = new SmartEvent(_naviMenu, "drag,start,down");
+ _draggedDownCallback.On += (s, e) =>
+ {
+ if (_header.TrackObject.IsVisible)
+ {
+ Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.EdgeTop));
+ }
+ else
+ {
+ Dragged?.Invoke(this, new DraggedEventArgs(DraggedState.Down));
+ }
+ };
+
+ _outterBox.PackEnd(_naviMenu);
+ _outterBox.PackEnd(_surfaceLayout);
+
+ _surfaceLayout.StackAbove(_naviMenu);
+
+ _defaultClass = new GenItemClass("1icon_1text")
+ {
+ GetTextHandler = (obj, part) =>
+ {
+ if (part == "elm.text")
+ {
+ return (obj as Item).Text;
+ }
+ return null;
+ },
+ GetContentHandler = (obj, part) =>
+ {
+ if (part == "elm.swallow.icon" && obj is Item menuItem && !string.IsNullOrEmpty(menuItem.Icon))
+ {
+ var icon = new ElmSharp.Image(Xamarin.Forms.Forms.NativeParent)
+ {
+ AlignmentX = -1,
+ AlignmentY = -1,
+ WeightX = 1.0,
+ WeightY = 1.0,
+ MinimumWidth = _dafaultIconSize,
+ MinimumHeight = _dafaultIconSize,
+ };
+ icon.Show();
+ icon.Load(menuItem.Icon);
+ return icon;
+ }
+ return null;
+ }
+ };
+
+ _naviMenu.ItemSelected += OnItemSelected;
+
+ }
+
+ void OnItemSelected(object sender, GenListItemEventArgs e)
+ {
+ ItemSelected?.Invoke(this, new SelectedItemChangedEventArgs((e.Item.Data as Item).Source, -1));
+ }
+
+ void OnLayout()
+ {
+ _surfaceLayout.Geometry = Geometry;
+ _naviMenu.Geometry = Geometry;
+ }
+
+ bool IsUpdated(List> items)
+ {
+ if (_itemCache == null)
+ return true;
+
+ if (_itemCache.Count != items.Count)
+ return true;
+
+ for (int i = 0; i < items.Count; i++)
+ {
+ if (_itemCache[i].Count != items[i].Count)
+ return true;
+
+ for (int j = 0; j < items[i].Count; j++)
+ {
+ if (_itemCache[i][j] != items[i][j])
+ return true;
+ }
+ }
+ return false;
+ }
+
+ }
+ public enum DraggedState
+ {
+ EdgeTop,
+ Up,
+ Down,
+ EdgeBottom,
+ }
+
+ public class DraggedEventArgs
+ {
+ public DraggedState State { get; private set; }
+
+ public DraggedEventArgs(DraggedState state)
+ {
+ State = state;
+ }
+ }
+
+ static class FileImageSourceEX
+ {
+ public static string ToAbsPath(this FileImageSource source)
+ {
+ return ResourcePath.GetPath(source.File);
+ }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs
new file mode 100644
index 00000000..d6f31cb8
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellContentRenderer.cs
@@ -0,0 +1,40 @@
+using ElmSharp;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class ShellContentRenderer : IShellItemRenderer
+ {
+ public ShellContentRenderer(ShellContent content)
+ {
+ ShellContent = content;
+ NativeView = GetNativeView(content);
+ }
+
+ public ShellContent ShellContent { get; protected set; }
+
+ public BaseShellItem Item => ShellContent;
+
+ public EvasObject NativeView { get; protected set; }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ NativeView?.Unrealize();
+ }
+ }
+
+ static EvasObject GetNativeView(ShellContent content)
+ {
+ var page = (content as IShellContentController).GetOrCreateContent();
+ return Platform.GetOrCreateRenderer(page).NativeView;
+ }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs
new file mode 100644
index 00000000..9f74894d
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellItemRenderer.cs
@@ -0,0 +1,97 @@
+using ElmSharp;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Xamarin.Forms;
+using XForms = Xamarin.Forms.Forms;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class ShellItemRenderer : IShellItemRenderer
+ {
+ Box _mainLayout;
+ EvasObject _currentItem;
+ Dictionary _rendererCache = new Dictionary();
+
+ public ShellItemRenderer(ShellItem item)
+ {
+ ShellItem = item;
+ ShellItem.PropertyChanged += OnItemPropertyChanged;
+ InitializeComponent();
+ UpdateCurrentItem();
+ }
+
+ public ShellItem ShellItem { get; protected set; }
+
+ public BaseShellItem Item => ShellItem;
+
+ public EvasObject NativeView => _mainLayout;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ ResetCurrentItem();
+ ShellItem.PropertyChanged -= OnItemPropertyChanged;
+ }
+ }
+
+ void InitializeComponent()
+ {
+ _mainLayout = new Box(XForms.NativeParent);
+ _mainLayout.SetLayoutCallback(OnLayout);
+ }
+
+ void UpdateCurrentItem()
+ {
+ ResetCurrentItem();
+ var currentItem = ShellItem.CurrentItem;
+ if (currentItem != null)
+ {
+ if (!_rendererCache.TryGetValue(currentItem, out IShellItemRenderer renderer))
+ {
+ renderer = ShellRendererFactory.Default.CreateShellNavigationRenderer(currentItem);
+ _rendererCache[currentItem] = renderer;
+ }
+ SetCurrentItem(renderer.NativeView);
+ }
+ }
+
+ void SetCurrentItem(EvasObject item)
+ {
+ _currentItem = item;
+ _currentItem.Show();
+ _mainLayout.PackEnd(_currentItem);
+ }
+
+ void ResetCurrentItem()
+ {
+ if (_currentItem != null)
+ {
+ _mainLayout.UnPack(_currentItem);
+ _currentItem.Hide();
+ _currentItem = null;
+ }
+ }
+
+ void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(ShellItem.CurrentItem))
+ {
+ UpdateCurrentItem();
+ }
+ }
+
+ void OnLayout()
+ {
+ if (_currentItem != null)
+ {
+ _currentItem.Geometry = _mainLayout.Geometry;
+ }
+ }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs
new file mode 100644
index 00000000..6e53ef8d
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRenderer.cs
@@ -0,0 +1,202 @@
+using ElmSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Tizen;
+using XForms = Xamarin.Forms.Forms;
+using XShell = Xamarin.Forms.Shell;
+
+[assembly: ExportRenderer(typeof(XShell), typeof(Tizen.Wearable.CircularUI.Forms.Renderer.ShellRenderer))]
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class ShellRenderer : VisualElementRenderer
+ {
+ NavigationDrawer _drawer;
+ NavigationView _navigationView;
+
+ Dictionary _rendererCache = new Dictionary();
+
+ public ShellRenderer()
+ {
+ RegisterPropertyHandler(XShell.CurrentItemProperty, UpdateCurrentItem);
+ RegisterPropertyHandler(XShell.FlyoutIsPresentedProperty, UpdateFlyoutIsPresented);
+ RegisterPropertyHandler(XShell.FlyoutBehaviorProperty, UpdateFlyoutBehavior);
+ RegisterPropertyHandler(XShell.FlyoutIconProperty, UpdateFlyoutIcon);
+ }
+
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ InitializeComponent();
+ base.OnElementChanged(e);
+ }
+
+ protected override void OnElementReady()
+ {
+ base.OnElementReady();
+ UpdateFlyoutMenu();
+ (Element as IShellController).StructureChanged += OnNavigationStructureChanged;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ foreach (var renderer in _rendererCache.Values)
+ {
+ renderer.Dispose();
+ }
+ (Element as IShellController).StructureChanged -= OnNavigationStructureChanged;
+ }
+ base.Dispose(disposing);
+ }
+
+ void InitializeComponent()
+ {
+ if (_drawer == null)
+ {
+ _drawer = new NavigationDrawer(XForms.NativeParent);
+ _drawer.IsOpen = Element.FlyoutIsPresented;
+ _drawer.Toggled += OnNavigationDrawerToggled;
+ SetNativeView(_drawer);
+ }
+ }
+
+ void OnNavigationStructureChanged(object sender, EventArgs e)
+ {
+ UpdateFlyoutMenu();
+ }
+
+ void UpdateFlyoutMenu()
+ {
+ if (Element.FlyoutBehavior == FlyoutBehavior.Disabled)
+ return;
+
+ var flyoutItems = (Element as IShellController).GenerateFlyoutGrouping();
+ if (flyoutItems.Count > 1)
+ {
+ InitializeNavigationDrawer();
+ _navigationView.Build(flyoutItems);
+ }
+ else
+ {
+ DeinitializeNavigationView();
+ }
+ }
+
+ void InitializeNavigationDrawer()
+ {
+ if (_navigationView != null)
+ {
+ return;
+ }
+
+ _navigationView = new NavigationView(XForms.NativeParent)
+ {
+ AlignmentX = -1,
+ AlignmentY = -1,
+ WeightX = 1,
+ WeightY = 1,
+ };
+ _navigationView.Show();
+ _navigationView.ItemSelected += OnMenuItemSelected;
+
+ _drawer.SetDrawerContent(_navigationView);
+ }
+
+ void OnNavigationDrawerToggled(object sender, EventArgs e)
+ {
+ if (_drawer.IsOpen)
+ {
+ _navigationView.Activate();
+ }
+ else
+ {
+ _navigationView.Deactivate();
+
+ var stack = (Element.CurrentItem.CurrentItem as ShellSection)?.Stack;
+ var currentPage = stack?.LastOrDefault();
+
+ if (currentPage == null)
+ {
+ currentPage = (Element.CurrentItem.CurrentItem.CurrentItem as IShellContentController)?.Page;
+ }
+
+ if (currentPage != null)
+ {
+ var renderer = Platform.GetOrCreateRenderer(currentPage);
+ (renderer as CirclePageRenderer)?.UpdateRotaryFocusObject(false);
+ }
+ }
+
+ Element.SetValueFromRenderer(XShell.FlyoutIsPresentedProperty, _drawer.IsOpen);
+ }
+
+ void DeinitializeNavigationView()
+ {
+ if (_navigationView == null)
+ return;
+ _drawer.SetDrawerContent(null);
+ _navigationView.Unrealize();
+ _navigationView = null;
+ }
+
+ void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e)
+ {
+ ((IShellController)Element).OnFlyoutItemSelected(e.SelectedItem as Element);
+ }
+
+ void UpdateCurrentItem()
+ {
+ ResetCurrentItem();
+ if (Element.CurrentItem != null)
+ {
+ if (!_rendererCache.TryGetValue(Element.CurrentItem, out IShellItemRenderer renderer))
+ {
+ renderer = ShellRendererFactory.Default.CreateItemRenderer(Element.CurrentItem);
+ _rendererCache[Element.CurrentItem] = renderer;
+ }
+ SetCurrentItem(renderer.NativeView);
+ }
+ }
+
+ void UpdateFlyoutBehavior()
+ {
+ if (Element.FlyoutBehavior == FlyoutBehavior.Disabled)
+ {
+ DeinitializeNavigationView();
+ }
+ else if (Element.FlyoutBehavior == FlyoutBehavior.Flyout)
+ {
+ UpdateFlyoutMenu();
+ }
+ else if (Element.FlyoutBehavior == FlyoutBehavior.Locked)
+ {
+ // Locked behavior is not supported on circularshell
+ }
+ }
+
+ void UpdateFlyoutIcon(bool init)
+ {
+ if (init && Element.FlyoutIcon == null)
+ return;
+
+ _drawer.UpdateDrawerIcon(Element.FlyoutIcon);
+ }
+
+ void UpdateFlyoutIsPresented()
+ {
+ _drawer.IsOpen = Element.FlyoutIsPresented;
+ }
+
+ void SetCurrentItem(EvasObject item)
+ {
+ _drawer.SetMainContent(item);
+ }
+
+ void ResetCurrentItem()
+ {
+ _drawer.SetMainContent(null);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs
new file mode 100644
index 00000000..e24034c6
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellRendererFactory.cs
@@ -0,0 +1,53 @@
+using Xamarin.Forms;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class ShellRendererFactory
+ {
+ static ShellRendererFactory _instance;
+ public static ShellRendererFactory Default
+ {
+ get
+ {
+ if (_instance == null)
+ {
+ _instance = new ShellRendererFactory();
+ }
+ return _instance;
+ }
+ set
+ {
+ _instance = value;
+ }
+
+ }
+
+ public virtual IShellItemRenderer CreateItemRenderer(ShellItem item)
+ {
+ if (item.Items.Count == 1)
+ {
+ return CreateShellNavigationRenderer(item.CurrentItem);
+ }
+ return new ShellItemRenderer(item);
+ }
+
+ public virtual IShellItemRenderer CreateShellNavigationRenderer(ShellSection item)
+ {
+ return new ShellSectionNavigationRenderer(item);
+ }
+
+ public virtual IShellItemRenderer CreateItemRenderer(ShellSection item)
+ {
+ if (item.Items.Count == 1)
+ {
+ return CreateItemRenderer(item.CurrentItem);
+ }
+ return new ShellSectionItemsRenderer(item);
+ }
+
+ public virtual IShellItemRenderer CreateItemRenderer(ShellContent item)
+ {
+ return new ShellContentRenderer(item);
+ }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs
new file mode 100644
index 00000000..7b6d684e
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionItemsRenderer.cs
@@ -0,0 +1,290 @@
+using ElmSharp;
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using Xamarin.Forms;
+using XForms = Xamarin.Forms.Forms;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ public class ShellSectionItemsRenderer : IShellItemRenderer
+ {
+ const int ItemMaxCount = 20;
+ const int OddMiddleItem = 10;
+ const int EvenMiddleItem = 11;
+
+ Box _mainLayout;
+ Index _indexIndicator;
+ Scroller _scroller;
+ Box _innerContainer;
+ List _items = new List();
+
+ int _currentIndex = -1;
+ Rect _lastLayoutBound;
+ int _updateByCode;
+
+
+ public ShellSectionItemsRenderer(ShellSection shellSection)
+ {
+ ShellSection = shellSection;
+ ShellSection.PropertyChanged += OnSectionPropertyChanged;
+ (ShellSection.Items as INotifyCollectionChanged).CollectionChanged += OnItemsChanged;
+ InitializeComponent();
+ UpdateItems();
+ }
+
+ public ShellSection ShellSection { get; protected set; }
+
+ public BaseShellItem Item => ShellSection;
+
+ public EvasObject NativeView => _mainLayout;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _mainLayout?.Unrealize();
+ (ShellSection.Items as INotifyCollectionChanged).CollectionChanged -= OnItemsChanged;
+ ShellSection.PropertyChanged -= OnSectionPropertyChanged;
+ }
+ }
+
+ void InitializeComponent()
+ {
+ _mainLayout = new Box(XForms.NativeParent)
+ {
+ AlignmentX = -1,
+ AlignmentY = -1,
+ WeightX = 1,
+ WeightY = 1,
+ };
+ _mainLayout.Show();
+ _mainLayout.SetLayoutCallback(OnLayout);
+
+ _indexIndicator = new Index(_mainLayout)
+ {
+ IsHorizontal = true,
+ AutoHide = false,
+ Style = IndexStyle.Circle,
+ };
+ _indexIndicator.Show();
+
+ _scroller = new Scroller(_mainLayout);
+ _scroller.PageScrolled += OnPageScrolled;
+ _scroller.DragStart += OnDragStarted;
+
+ // Disables the visibility of the scrollbar in both directions:
+ _scroller.HorizontalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible;
+ _scroller.VerticalScrollBarVisiblePolicy = ScrollBarVisiblePolicy.Invisible;
+ // Sets the limit of scroll to one page maximum:
+ _scroller.HorizontalPageScrollLimit = 1;
+ _scroller.SetPageSize(1.0, 1.0);
+ _scroller.SetAlignment(-1, -1);
+ _scroller.SetWeight(1.0, 1.0);
+ _scroller.Show();
+
+ _innerContainer = new Box(_mainLayout);
+ _innerContainer.SetLayoutCallback(OnInnerLayoutUpdate);
+ _innerContainer.SetAlignment(-1, -1);
+ _innerContainer.SetWeight(1.0, 1.0);
+ _innerContainer.Show();
+ _scroller.SetContent(_innerContainer);
+
+ _mainLayout.PackEnd(_indexIndicator);
+ _mainLayout.PackEnd(_scroller);
+ _indexIndicator.StackAbove(_scroller);
+ }
+
+ void OnDragStarted(object sender, EventArgs e)
+ {
+ if (_currentIndex - 1 >= 0 && !_items[_currentIndex - 1].IsRealized)
+ {
+ RealizeItem(_items[_currentIndex - 1]);
+ }
+ if (_currentIndex + 1 < _items.Count && !_items[_currentIndex + 1].IsRealized)
+ {
+ RealizeItem(_items[_currentIndex + 1]);
+ }
+ }
+
+ void UpdateItems()
+ {
+ _items.Clear();
+ _indexIndicator.Clear();
+ _innerContainer.UnPackAll();
+ _lastLayoutBound = default(Rect);
+
+ foreach (var item in ShellSection.Items)
+ {
+ var indexItem = _indexIndicator.Append(null);
+ indexItem.Style = GetItemStyle(ShellSection.Items.Count, _items.Count);
+ _items.Add(new ItemHolder
+ {
+ IsRealized = false,
+ IndexItem = indexItem,
+ Item = item
+ });
+ }
+ _indexIndicator.Update(0);
+ UpdateCurrentPage(ShellSection.Items.IndexOf(ShellSection.CurrentItem));
+ }
+
+ void RealizeItem(ItemHolder item)
+ {
+ var renderer = ShellRendererFactory.Default.CreateItemRenderer(item.Item);
+ renderer.NativeView.Show();
+ item.NativeView = renderer.NativeView;
+ item.IsRealized = true;
+ _innerContainer.PackEnd(item.NativeView);
+ item.NativeView.StackBelow(_indexIndicator);
+ item.NativeView.Geometry = item.Bound;
+ }
+
+ void UpdateCurrentPage(int index)
+ {
+ if (_currentIndex == index)
+ return;
+
+ _currentIndex = index;
+ UpdateCurrentIndexIndicator();
+ if (!_items[index].IsRealized)
+ {
+ RealizeItem(_items[index]);
+ }
+ UpdateFocusPolicy();
+ }
+
+ void UpdateFocusPolicy()
+ {
+ foreach (var item in _items)
+ {
+ if (item.IsRealized)
+ {
+ if (item.NativeView is ElmSharp.Widget widget)
+ {
+ widget.AllowTreeFocus = (_items[_currentIndex] == item);
+ }
+ }
+ }
+ }
+
+ void UpdateCurrentIndexIndicator()
+ {
+ if (_currentIndex >= 0 && _currentIndex < _items.Count)
+ {
+ _items[_currentIndex].IndexItem.Select(true);
+ }
+ }
+ void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ UpdateItems();
+ }
+
+ void OnPageScrolled(object sender, EventArgs e)
+ {
+ if (_updateByCode > 0)
+ {
+ return;
+ }
+
+ if (_currentIndex < 0 || ShellSection.Items.Count <= _currentIndex)
+ {
+ return;
+ }
+
+ UpdateCurrentPage(_scroller.HorizontalPageIndex);
+ var currentItem = ShellSection.Items[_currentIndex];
+ ShellSection.SetValueFromRenderer(ShellSection.CurrentItemProperty, currentItem);
+ }
+
+ void OnSectionPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == nameof(ShellSection.CurrentItem))
+ {
+ var newIndex = ShellSection.Items.IndexOf(ShellSection.CurrentItem);
+ if (_currentIndex != newIndex)
+ {
+ UpdateCurrentPage(newIndex);
+ _updateByCode++;
+ _scroller.ScrollTo(newIndex, 0, false);
+ _updateByCode--;
+ }
+ }
+ }
+
+ void OnLayout()
+ {
+ _indexIndicator.Geometry = _mainLayout.Geometry;
+ _scroller.Geometry = _mainLayout.Geometry;
+ }
+
+ void OnInnerLayoutUpdate()
+ {
+ if (_lastLayoutBound == _innerContainer.Geometry)
+ {
+ return;
+ }
+ _lastLayoutBound = _innerContainer.Geometry;
+
+ var layoutBound = _innerContainer.Geometry.Size;
+ int baseX = _innerContainer.Geometry.X;
+
+ Rect bound = _scroller.Geometry;
+ int index = 0;
+ foreach (var item in _items)
+ {
+ bound.X = baseX + index * bound.Width;
+ item.Bound = bound;
+ if (item.IsRealized)
+ {
+ item.NativeView.Geometry = bound;
+ }
+ index++;
+ }
+ _innerContainer.MinimumWidth = _items.Count * bound.Width;
+
+ if (_items.Count > _currentIndex && _currentIndex >= 0)
+ {
+ _updateByCode++;
+ _scroller.ScrollTo(_currentIndex, 0, false);
+ _updateByCode--;
+ }
+ }
+
+ static string GetItemStyle(int itemCount, int offset)
+ {
+ string returnValue = string.Empty;
+ int startItem;
+ int styleNumber;
+
+ if (itemCount % 2 == 0) //Item count is even.
+ {
+ startItem = EvenMiddleItem - itemCount / 2;
+ styleNumber = startItem + offset;
+ returnValue = "item/even_" + styleNumber;
+ }
+ else //Item count is odd.
+ {
+ startItem = OddMiddleItem - itemCount / 2;
+ styleNumber = startItem + offset;
+ returnValue = "item/odd_" + styleNumber;
+ }
+ return returnValue;
+ }
+
+ class ItemHolder
+ {
+ public bool IsRealized { get; set; }
+ public Rect Bound { get; set; }
+ public EvasObject NativeView { get; set; }
+ public IndexItem IndexItem { get; set; }
+ public ShellContent Item { get; set; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs
new file mode 100644
index 00000000..7a860e7e
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Shell/ShellSectionNavigationRenderer.cs
@@ -0,0 +1,208 @@
+using ElmSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform.Tizen;
+using XForms = Xamarin.Forms.Forms;
+
+namespace Tizen.Wearable.CircularUI.Forms.Renderer
+{
+ class SimpleViewStack : Box
+ {
+ EvasObject _lastTop;
+
+ public SimpleViewStack(EvasObject parent) : base(parent)
+ {
+ InternalStack = new List();
+ SetLayoutCallback(OnLayout);
+ }
+
+ List InternalStack { get; set; }
+
+ public IReadOnlyList Stack => InternalStack;
+
+ public void Push(EvasObject view)
+ {
+ InternalStack.Add(view);
+ PackEnd(view);
+ UpdateTopView();
+ }
+
+ public void Pop()
+ {
+ if (_lastTop != null)
+ {
+ var tobeRemoved = _lastTop;
+ InternalStack.Remove(tobeRemoved);
+ UnPack(tobeRemoved);
+ UpdateTopView();
+
+ // if Pop was called by removed page,
+ // Unrealize cause deletation of NativeCallback, it could be a cause of crash
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ tobeRemoved.Unrealize();
+ });
+ }
+ }
+
+ public void PopToRoot()
+ {
+ while (InternalStack.Count > 1)
+ {
+ Pop();
+ }
+ }
+
+ public void Insert(EvasObject before, EvasObject view)
+ {
+ view.Hide();
+ var idx = InternalStack.IndexOf(before);
+ InternalStack.Insert(idx, view);
+ PackEnd(view);
+ UpdateTopView();
+ }
+
+ public void Remove(EvasObject view)
+ {
+ InternalStack.Remove(view);
+ UnPack(view);
+ UpdateTopView();
+ Device.BeginInvokeOnMainThread(() =>
+ {
+ view?.Unrealize();
+ });
+ }
+
+ void UpdateTopView()
+ {
+ if (_lastTop != InternalStack.LastOrDefault())
+ {
+ _lastTop?.Hide();
+ _lastTop = InternalStack.LastOrDefault();
+ _lastTop.Show();
+ }
+ }
+
+ void OnLayout()
+ {
+ foreach (var view in Stack)
+ {
+ view.Geometry = Geometry;
+ }
+ }
+
+ }
+
+ public class ShellSectionNavigationRenderer : IShellItemRenderer
+ {
+ SimpleViewStack _viewStack;
+ IShellItemRenderer _rootPageRenderer;
+
+ public ShellSectionNavigationRenderer(ShellSection item)
+ {
+ ShellSection = item;
+ (ShellSection as IShellSectionController).NavigationRequested += OnNavigationRequested;
+ InitializeComponent();
+ }
+
+ public ShellSection ShellSection { get; protected set; }
+
+ public BaseShellItem Item => ShellSection;
+
+ public EvasObject NativeView => _viewStack;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ _rootPageRenderer?.Dispose();
+ _viewStack?.Unrealize();
+ (ShellSection as IShellSectionController).NavigationRequested -= OnNavigationRequested;
+ }
+ }
+
+ void InitializeComponent()
+ {
+ _viewStack = new SimpleViewStack(XForms.NativeParent);
+ _viewStack.Show();
+
+ _rootPageRenderer = ShellRendererFactory.Default.CreateItemRenderer(ShellSection);
+ _viewStack.Push(_rootPageRenderer.NativeView);
+ }
+
+ void OnInsertRequest(NavigationRequestedEventArgs request)
+ {
+ var before = Platform.GetRenderer(request.BeforePage)?.NativeView ?? null;
+ if (before == null)
+ {
+ request.Task = Task.FromException(new ArgumentException("Can't found page on stack", nameof(request.BeforePage)));
+ return;
+ }
+ var renderer = Platform.GetOrCreateRenderer(request.Page);
+ _viewStack.Insert(before, renderer.NativeView);
+ request.Task = Task.FromResult(true);
+ }
+
+ void OnPushRequest(NavigationRequestedEventArgs request)
+ {
+ var renderer = Platform.GetOrCreateRenderer(request.Page);
+ _viewStack.Push(renderer.NativeView);
+ request.Task = Task.FromResult(true);
+ }
+
+ void OnPopRequest(NavigationRequestedEventArgs request)
+ {
+ _viewStack.Pop();
+ request.Task = Task.FromResult(true);
+ }
+
+ void OnPopToRootRequest(NavigationRequestedEventArgs request)
+ {
+ _viewStack.PopToRoot();
+ request.Task = Task.FromResult(true);
+ }
+
+ void OnRemoveRequest(NavigationRequestedEventArgs request)
+ {
+ var renderer = Platform.GetRenderer(request.Page);
+ if (renderer == null)
+ {
+ request.Task = Task.FromException(new ArgumentException("Can't found page on stack", nameof(request.Page)));
+ return;
+ }
+ _viewStack.Remove(renderer.NativeView);
+ request.Task = Task.FromResult(true);
+ }
+
+ void OnNavigationRequested(object sender, NavigationRequestedEventArgs e)
+ {
+ switch (e.RequestType)
+ {
+ case NavigationRequestType.Insert:
+ OnInsertRequest(e);
+ break;
+ case NavigationRequestType.Push:
+ OnPushRequest(e);
+ break;
+ case NavigationRequestType.Pop:
+ OnPopRequest(e);
+ break;
+ case NavigationRequestType.PopToRoot:
+ OnPopToRootRequest(e);
+ break;
+ case NavigationRequestType.Remove:
+ OnRemoveRequest(e);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Tizen.Wearable.CircularUI.Forms.Renderer.csproj b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Tizen.Wearable.CircularUI.Forms.Renderer.csproj
index 4f879ed9..fe9b2802 100644
--- a/src/Tizen.Wearable.CircularUI.Forms.Renderer/Tizen.Wearable.CircularUI.Forms.Renderer.csproj
+++ b/src/Tizen.Wearable.CircularUI.Forms.Renderer/Tizen.Wearable.CircularUI.Forms.Renderer.csproj
@@ -6,7 +6,9 @@
+
+
diff --git a/src/Tizen.Wearable.CircularUI.Forms.Renderer/res/drag_handle_white_18dp.png b/src/Tizen.Wearable.CircularUI.Forms.Renderer/res/drag_handle_white_18dp.png
new file mode 100644
index 00000000..5d656b06
Binary files /dev/null and b/src/Tizen.Wearable.CircularUI.Forms.Renderer/res/drag_handle_white_18dp.png differ
diff --git a/src/Tizen.Wearable.CircularUI.Forms/CirclePage.cs b/src/Tizen.Wearable.CircularUI.Forms/CirclePage.cs
old mode 100755
new mode 100644
index a92a2a23..0ef6da03
--- a/src/Tizen.Wearable.CircularUI.Forms/CirclePage.cs
+++ b/src/Tizen.Wearable.CircularUI.Forms/CirclePage.cs
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
+using System.ComponentModel;
using Xamarin.Forms;
namespace Tizen.Wearable.CircularUI.Forms
@@ -62,6 +62,9 @@ public CirclePage()
/// 4
public IList CircleSurfaceItems { get; }
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool Appeared { get; set; }
+
///
/// Gets or sets ActionButton that presents a menu item and associates it with a command
///
@@ -92,6 +95,18 @@ protected override void OnBindingContextChanged()
}
}
+ protected override void OnAppearing()
+ {
+ base.OnAppearing();
+ Appeared = true;
+ }
+
+ protected override void OnDisappearing()
+ {
+ base.OnDisappearing();
+ Appeared = false;
+ }
+
void OnSurfaceItemsChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if (args.Action != NotifyCollectionChangedAction.Add) return;
diff --git a/src/Tizen.Wearable.CircularUI.Forms/CircularShell.cs b/src/Tizen.Wearable.CircularUI.Forms/CircularShell.cs
new file mode 100644
index 00000000..db8d1acd
--- /dev/null
+++ b/src/Tizen.Wearable.CircularUI.Forms/CircularShell.cs
@@ -0,0 +1,17 @@
+using Xamarin.Forms;
+
+namespace Tizen.Wearable.CircularUI.Forms
+{
+ public class CircularShell : Shell
+ {
+ protected override bool OnBackButtonPressed()
+ {
+ if (FlyoutIsPresented)
+ {
+ FlyoutIsPresented = false;
+ return true;
+ }
+ return base.OnBackButtonPressed();
+ }
+ }
+}
diff --git a/src/Tizen.Wearable.CircularUI.Forms/Tizen.Wearable.CircularUI.Forms.csproj b/src/Tizen.Wearable.CircularUI.Forms/Tizen.Wearable.CircularUI.Forms.csproj
index 0a73eb38..bc641ba2 100644
--- a/src/Tizen.Wearable.CircularUI.Forms/Tizen.Wearable.CircularUI.Forms.csproj
+++ b/src/Tizen.Wearable.CircularUI.Forms/Tizen.Wearable.CircularUI.Forms.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/test/SimpleTextWatchface/SimpleTextWatchface.csproj b/test/SimpleTextWatchface/SimpleTextWatchface.csproj
index b7936a80..68ff24e2 100644
--- a/test/SimpleTextWatchface/SimpleTextWatchface.csproj
+++ b/test/SimpleTextWatchface/SimpleTextWatchface.csproj
@@ -1,6 +1,5 @@
-
+
-
Exetizen40
@@ -20,11 +19,7 @@
-
- Runtime
-
-
-
+
diff --git a/test/SimpleWidgetApp/SimpleWidgetApp.csproj b/test/SimpleWidgetApp/SimpleWidgetApp.csproj
index 06ee98ee..357c1eba 100644
--- a/test/SimpleWidgetApp/SimpleWidgetApp.csproj
+++ b/test/SimpleWidgetApp/SimpleWidgetApp.csproj
@@ -1,13 +1,13 @@
-
+Exe
- 4.0.0tizen40
+
-
+
diff --git a/test/WearableUIGallery/WearableUIGallery.Tizen.Wearable/WearableUIGallery.Tizen.Wearable.csproj b/test/WearableUIGallery/WearableUIGallery.Tizen.Wearable/WearableUIGallery.Tizen.Wearable.csproj
index 0eb409d6..d3be8293 100644
--- a/test/WearableUIGallery/WearableUIGallery.Tizen.Wearable/WearableUIGallery.Tizen.Wearable.csproj
+++ b/test/WearableUIGallery/WearableUIGallery.Tizen.Wearable/WearableUIGallery.Tizen.Wearable.csproj
@@ -1,6 +1,5 @@
-
Exetizen40
diff --git a/test/WearableUIGallery/WearableUIGallery/WearableUIGallery.csproj b/test/WearableUIGallery/WearableUIGallery/WearableUIGallery.csproj
index 7376194b..a797194a 100644
--- a/test/WearableUIGallery/WearableUIGallery/WearableUIGallery.csproj
+++ b/test/WearableUIGallery/WearableUIGallery/WearableUIGallery.csproj
@@ -6,7 +6,7 @@
-
+