From ed09456d57eab81510c9f66760feead3ce6f7cbd Mon Sep 17 00:00:00 2001 From: logikonline Date: Sun, 21 Dec 2025 13:41:52 -0500 Subject: [PATCH] Move samples to dedicated repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Samples are now in https://github.com/open-maui/maui-linux-samples This keeps the framework repo focused and allows samples to: - Reference NuGet package (real-world usage) - Be cloned independently - Have their own release cycle 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- README.md | 11 +- samples/ShellDemo/App.cs | 78 --- samples/ShellDemo/MauiProgram.cs | 24 - samples/ShellDemo/Pages/AboutPage.cs | 115 ---- samples/ShellDemo/Pages/ButtonsPage.cs | 229 ------- samples/ShellDemo/Pages/ControlsPage.cs | 203 ------- samples/ShellDemo/Pages/DetailPage.cs | 123 ---- samples/ShellDemo/Pages/GridsPage.cs | 594 ------------------- samples/ShellDemo/Pages/HomePage.cs | 265 --------- samples/ShellDemo/Pages/ListsPage.cs | 249 -------- samples/ShellDemo/Pages/PickersPage.cs | 261 -------- samples/ShellDemo/Pages/ProgressPage.cs | 261 -------- samples/ShellDemo/Pages/SelectionPage.cs | 239 -------- samples/ShellDemo/Pages/TextInputPage.cs | 166 ------ samples/ShellDemo/Platforms/Linux/Program.cs | 19 - samples/ShellDemo/README.md | 157 ----- samples/ShellDemo/ShellDemo.csproj | 15 - samples/TodoApp/App.cs | 21 - samples/TodoApp/MauiProgram.cs | 22 - samples/TodoApp/NewTodoPage.xaml | 79 --- samples/TodoApp/NewTodoPage.xaml.cs | 31 - samples/TodoApp/Program.cs | 67 --- samples/TodoApp/README.md | 111 ---- samples/TodoApp/TodoApp.csproj | 15 - samples/TodoApp/TodoDetailPage.xaml | 106 ---- samples/TodoApp/TodoDetailPage.xaml.cs | 91 --- samples/TodoApp/TodoItem.cs | 81 --- samples/TodoApp/TodoListPage.xaml | 129 ---- samples/TodoApp/TodoListPage.xaml.cs | 174 ------ samples/TodoApp/TodoService.cs | 61 -- 30 files changed, 10 insertions(+), 3987 deletions(-) delete mode 100644 samples/ShellDemo/App.cs delete mode 100644 samples/ShellDemo/MauiProgram.cs delete mode 100644 samples/ShellDemo/Pages/AboutPage.cs delete mode 100644 samples/ShellDemo/Pages/ButtonsPage.cs delete mode 100644 samples/ShellDemo/Pages/ControlsPage.cs delete mode 100644 samples/ShellDemo/Pages/DetailPage.cs delete mode 100644 samples/ShellDemo/Pages/GridsPage.cs delete mode 100644 samples/ShellDemo/Pages/HomePage.cs delete mode 100644 samples/ShellDemo/Pages/ListsPage.cs delete mode 100644 samples/ShellDemo/Pages/PickersPage.cs delete mode 100644 samples/ShellDemo/Pages/ProgressPage.cs delete mode 100644 samples/ShellDemo/Pages/SelectionPage.cs delete mode 100644 samples/ShellDemo/Pages/TextInputPage.cs delete mode 100644 samples/ShellDemo/Platforms/Linux/Program.cs delete mode 100644 samples/ShellDemo/README.md delete mode 100644 samples/ShellDemo/ShellDemo.csproj delete mode 100644 samples/TodoApp/App.cs delete mode 100644 samples/TodoApp/MauiProgram.cs delete mode 100644 samples/TodoApp/NewTodoPage.xaml delete mode 100644 samples/TodoApp/NewTodoPage.xaml.cs delete mode 100644 samples/TodoApp/Program.cs delete mode 100644 samples/TodoApp/README.md delete mode 100644 samples/TodoApp/TodoApp.csproj delete mode 100644 samples/TodoApp/TodoDetailPage.xaml delete mode 100644 samples/TodoApp/TodoDetailPage.xaml.cs delete mode 100644 samples/TodoApp/TodoItem.cs delete mode 100644 samples/TodoApp/TodoListPage.xaml delete mode 100644 samples/TodoApp/TodoListPage.xaml.cs delete mode 100644 samples/TodoApp/TodoService.cs diff --git a/README.md b/README.md index a4a9675..21f4b11 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,16 @@ sudo dnf install libX11-devel libXrandr-devel libXcursor-devel libXi-devel mesa- - [API Reference](docs/API.md) - [Contributing Guide](CONTRIBUTING.md) -## Sample Application +## Sample Applications + +Full sample applications are available in the [maui-linux-samples](https://github.com/open-maui/maui-linux-samples) repository: + +| Sample | Description | +|--------|-------------| +| **[TodoApp](https://github.com/open-maui/maui-linux-samples/tree/main/TodoApp)** | Task manager with NavigationPage, XAML data binding, CollectionView | +| **[ShellDemo](https://github.com/open-maui/maui-linux-samples/tree/main/ShellDemo)** | Control showcase with Shell navigation and flyout menu | + +## Quick Example ```csharp using OpenMaui.Platform.Linux; diff --git a/samples/ShellDemo/App.cs b/samples/ShellDemo/App.cs deleted file mode 100644 index 2615a41..0000000 --- a/samples/ShellDemo/App.cs +++ /dev/null @@ -1,78 +0,0 @@ -// ShellDemo App - Comprehensive Control Demo - -using Microsoft.Maui.Controls; - -namespace ShellDemo; - -/// -/// Main application class with Shell navigation. -/// -public class App : Application -{ - public App() - { - MainPage = new AppShell(); - } -} - -/// -/// Shell definition with flyout menu - comprehensive control demo. -/// -public class AppShell : Shell -{ - public AppShell() - { - FlyoutBehavior = FlyoutBehavior.Flyout; - Title = "OpenMaui Controls Demo"; - - // Register routes for push navigation (pages not in flyout) - Routing.RegisterRoute("detail", typeof(DetailPage)); - - // Home - Items.Add(CreateFlyoutItem("Home", typeof(HomePage))); - - // Buttons Demo - Items.Add(CreateFlyoutItem("Buttons", typeof(ButtonsPage))); - - // Text Input Demo - Items.Add(CreateFlyoutItem("Text Input", typeof(TextInputPage))); - - // Selection Controls Demo - Items.Add(CreateFlyoutItem("Selection", typeof(SelectionPage))); - - // Pickers Demo - Items.Add(CreateFlyoutItem("Pickers", typeof(PickersPage))); - - // Lists Demo - Items.Add(CreateFlyoutItem("Lists", typeof(ListsPage))); - - // Progress Demo - Items.Add(CreateFlyoutItem("Progress", typeof(ProgressPage))); - - // Grids Demo - Items.Add(CreateFlyoutItem("Grids", typeof(GridsPage))); - - // About - Items.Add(CreateFlyoutItem("About", typeof(AboutPage))); - } - - private FlyoutItem CreateFlyoutItem(string title, Type pageType) - { - // Route is required for Shell.GoToAsync navigation to work - var route = title.Replace(" ", ""); - return new FlyoutItem - { - Title = title, - Route = route, - Items = - { - new ShellContent - { - Title = title, - Route = route, - ContentTemplate = new DataTemplate(pageType) - } - } - }; - } -} diff --git a/samples/ShellDemo/MauiProgram.cs b/samples/ShellDemo/MauiProgram.cs deleted file mode 100644 index 0ec2a7e..0000000 --- a/samples/ShellDemo/MauiProgram.cs +++ /dev/null @@ -1,24 +0,0 @@ -// MauiProgram.cs - Shared MAUI app configuration -// Works across all platforms (iOS, Android, Windows, Linux) - -using Microsoft.Maui.Hosting; -using Microsoft.Maui.Platform.Linux.Hosting; - -namespace ShellDemo; - -public static class MauiProgram -{ - public static MauiApp CreateMauiApp() - { - var builder = MauiApp.CreateBuilder(); - - // Configure the app (shared across all platforms) - builder.UseMauiApp(); - - // Add Linux platform support - // On other platforms, this would be iOS/Android/Windows specific - builder.UseLinux(); - - return builder.Build(); - } -} diff --git a/samples/ShellDemo/Pages/AboutPage.cs b/samples/ShellDemo/Pages/AboutPage.cs deleted file mode 100644 index e38d027..0000000 --- a/samples/ShellDemo/Pages/AboutPage.cs +++ /dev/null @@ -1,115 +0,0 @@ -// AboutPage - Information about OpenMaui Linux - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class AboutPage : ContentPage -{ - public AboutPage() - { - Title = "About"; - - Content = new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 20, - Children = - { - new Label - { - Text = "OpenMaui Linux", - FontSize = 32, - FontAttributes = FontAttributes.Bold, - TextColor = Color.FromArgb("#1A237E"), - HorizontalOptions = LayoutOptions.Center - }, - new Label - { - Text = "Version 1.0.0", - FontSize = 16, - TextColor = Colors.Gray, - HorizontalOptions = LayoutOptions.Center - }, - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Label - { - Text = "OpenMaui Linux brings .NET MAUI to Linux desktops using SkiaSharp for rendering. " + - "It provides a native Linux experience while maintaining compatibility with MAUI's cross-platform API.", - FontSize = 14, - LineBreakMode = LineBreakMode.WordWrap - }, - CreateInfoCard("Platform", "Linux (X11/Wayland)"), - CreateInfoCard("Rendering", "SkiaSharp"), - CreateInfoCard("Framework", ".NET MAUI"), - CreateInfoCard("License", "MIT License"), - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Label - { - Text = "Features", - FontSize = 20, - FontAttributes = FontAttributes.Bold - }, - CreateFeatureItem("Full XAML support with styles and resources"), - CreateFeatureItem("Shell navigation with flyout menus"), - CreateFeatureItem("All standard MAUI controls"), - CreateFeatureItem("Data binding and MVVM"), - CreateFeatureItem("Keyboard and mouse input"), - CreateFeatureItem("High DPI support"), - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Label - { - Text = "https://github.com/pablotoledo/OpenMaui-Linux", - FontSize = 12, - TextColor = Colors.Blue, - HorizontalOptions = LayoutOptions.Center - } - } - } - }; - } - - private Frame CreateInfoCard(string label, string value) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Color.FromArgb("#F5F5F5"), - HasShadow = false, - Content = new HorizontalStackLayout - { - Children = - { - new Label - { - Text = label + ":", - FontAttributes = FontAttributes.Bold, - WidthRequest = 100 - }, - new Label - { - Text = value, - TextColor = Colors.Gray - } - } - } - }; - } - - private View CreateFeatureItem(string text) - { - return new HorizontalStackLayout - { - Spacing = 10, - Children = - { - new Label { Text = "✓", TextColor = Color.FromArgb("#4CAF50"), FontSize = 16 }, - new Label { Text = text, FontSize = 14 } - } - }; - } -} diff --git a/samples/ShellDemo/Pages/ButtonsPage.cs b/samples/ShellDemo/Pages/ButtonsPage.cs deleted file mode 100644 index 695ae97..0000000 --- a/samples/ShellDemo/Pages/ButtonsPage.cs +++ /dev/null @@ -1,229 +0,0 @@ -// ButtonsPage - Comprehensive Button Control Demo - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class ButtonsPage : ContentPage -{ - private readonly Label _eventLog; - private int _eventCount = 0; - - public ButtonsPage() - { - Title = "Buttons Demo"; - - _eventLog = new Label - { - Text = "Events will appear here...", - FontSize = 11, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap - }; - - Content = new Grid - { - RowDefinitions = - { - new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, - new RowDefinition { Height = new GridLength(120) } - }, - Children = - { - CreateMainContent(), - CreateEventLogPanel() - } - }; - - Grid.SetRow((View)((Grid)Content).Children[0], 0); - Grid.SetRow((View)((Grid)Content).Children[1], 1); - } - - private View CreateMainContent() - { - return new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 20, - Children = - { - new Label { Text = "Button Styles & Events", FontSize = 24, FontAttributes = FontAttributes.Bold }, - - // Basic Buttons - CreateSection("Basic Buttons", CreateBasicButtons()), - - // Styled Buttons - CreateSection("Styled Buttons", CreateStyledButtons()), - - // Button States - CreateSection("Button States", CreateButtonStates()), - - // Button with Icons (text simulation) - CreateSection("Button Variations", CreateButtonVariations()) - } - } - }; - } - - private View CreateBasicButtons() - { - var layout = new VerticalStackLayout { Spacing = 10 }; - - var defaultBtn = new Button { Text = "Default Button" }; - defaultBtn.Clicked += (s, e) => LogEvent("Default Button clicked"); - defaultBtn.Pressed += (s, e) => LogEvent("Default Button pressed"); - defaultBtn.Released += (s, e) => LogEvent("Default Button released"); - - var textBtn = new Button { Text = "Text Only", BackgroundColor = Colors.Transparent, TextColor = Colors.Blue }; - textBtn.Clicked += (s, e) => LogEvent("Text Button clicked"); - - layout.Children.Add(defaultBtn); - layout.Children.Add(textBtn); - - return layout; - } - - private View CreateStyledButtons() - { - var layout = new HorizontalStackLayout { Spacing = 10 }; - - var colors = new[] - { - ("#2196F3", "Primary"), - ("#4CAF50", "Success"), - ("#FF9800", "Warning"), - ("#F44336", "Danger"), - ("#9C27B0", "Purple") - }; - - foreach (var (color, name) in colors) - { - var btn = new Button - { - Text = name, - BackgroundColor = Color.FromArgb(color), - TextColor = Colors.White, - CornerRadius = 5 - }; - btn.Clicked += (s, e) => LogEvent($"{name} button clicked"); - layout.Children.Add(btn); - } - - return layout; - } - - private View CreateButtonStates() - { - var layout = new VerticalStackLayout { Spacing = 10 }; - - var enabledBtn = new Button { Text = "Enabled Button", IsEnabled = true }; - enabledBtn.Clicked += (s, e) => LogEvent("Enabled button clicked"); - - var disabledBtn = new Button { Text = "Disabled Button", IsEnabled = false }; - - var toggleBtn = new Button { Text = "Toggle Above Button" }; - toggleBtn.Clicked += (s, e) => - { - disabledBtn.IsEnabled = !disabledBtn.IsEnabled; - disabledBtn.Text = disabledBtn.IsEnabled ? "Now Enabled!" : "Disabled Button"; - LogEvent($"Toggled button to: {(disabledBtn.IsEnabled ? "Enabled" : "Disabled")}"); - }; - - layout.Children.Add(enabledBtn); - layout.Children.Add(disabledBtn); - layout.Children.Add(toggleBtn); - - return layout; - } - - private View CreateButtonVariations() - { - var layout = new VerticalStackLayout { Spacing = 10 }; - - var wideBtn = new Button - { - Text = "Wide Button", - HorizontalOptions = LayoutOptions.Fill, - BackgroundColor = Color.FromArgb("#673AB7"), - TextColor = Colors.White - }; - wideBtn.Clicked += (s, e) => LogEvent("Wide button clicked"); - - var tallBtn = new Button - { - Text = "Tall Button", - HeightRequest = 60, - BackgroundColor = Color.FromArgb("#009688"), - TextColor = Colors.White - }; - tallBtn.Clicked += (s, e) => LogEvent("Tall button clicked"); - - var roundBtn = new Button - { - Text = "Round", - WidthRequest = 80, - HeightRequest = 80, - CornerRadius = 40, - BackgroundColor = Color.FromArgb("#E91E63"), - TextColor = Colors.White - }; - roundBtn.Clicked += (s, e) => LogEvent("Round button clicked"); - - layout.Children.Add(wideBtn); - layout.Children.Add(tallBtn); - layout.Children.Add(new HorizontalStackLayout { Children = { roundBtn } }); - - return layout; - } - - private Frame CreateSection(string title, View content) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - Content = new VerticalStackLayout - { - Spacing = 10, - Children = - { - new Label { Text = title, FontSize = 16, FontAttributes = FontAttributes.Bold }, - content - } - } - }; - } - - private View CreateEventLogPanel() - { - return new Frame - { - BackgroundColor = Color.FromArgb("#F5F5F5"), - Padding = new Thickness(10), - CornerRadius = 0, - Content = new VerticalStackLayout - { - Children = - { - new Label { Text = "Event Log:", FontSize = 12, FontAttributes = FontAttributes.Bold }, - new ScrollView - { - HeightRequest = 80, - Content = _eventLog - } - } - } - }; - } - - private void LogEvent(string message) - { - _eventCount++; - var timestamp = DateTime.Now.ToString("HH:mm:ss"); - _eventLog.Text = $"[{timestamp}] {_eventCount}. {message}\n{_eventLog.Text}"; - } -} diff --git a/samples/ShellDemo/Pages/ControlsPage.cs b/samples/ShellDemo/Pages/ControlsPage.cs deleted file mode 100644 index 6478bdc..0000000 --- a/samples/ShellDemo/Pages/ControlsPage.cs +++ /dev/null @@ -1,203 +0,0 @@ -// ControlsPage - Demonstrates various MAUI controls - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class ControlsPage : ContentPage -{ - public ControlsPage() - { - Title = "Controls"; - - Content = new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 15, - Children = - { - new Label - { - Text = "Control Gallery", - FontSize = 24, - FontAttributes = FontAttributes.Bold - }, - - // Buttons - CreateSection("Buttons", new View[] - { - CreateButtonRow() - }), - - // CheckBox & Switch - CreateSection("Selection", new View[] - { - CreateCheckBoxRow(), - CreateSwitchRow() - }), - - // Slider - CreateSection("Slider", new View[] - { - CreateSliderRow() - }), - - // Picker - CreateSection("Picker", new View[] - { - CreatePickerRow() - }), - - // Progress - CreateSection("Progress", new View[] - { - CreateProgressRow() - }) - } - } - }; - } - - private Frame CreateSection(string title, View[] content) - { - var layout = new VerticalStackLayout { Spacing = 10 }; - layout.Children.Add(new Label - { - Text = title, - FontSize = 18, - FontAttributes = FontAttributes.Bold - }); - - foreach (var view in content) - { - layout.Children.Add(view); - } - - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - Content = layout - }; - } - - private View CreateButtonRow() - { - var resultLabel = new Label { TextColor = Colors.Gray, FontSize = 12 }; - - var layout = new VerticalStackLayout { Spacing = 10 }; - - var buttonRow = new HorizontalStackLayout { Spacing = 10 }; - - var primaryBtn = new Button { Text = "Primary", BackgroundColor = Color.FromArgb("#2196F3"), TextColor = Colors.White }; - primaryBtn.Clicked += (s, e) => resultLabel.Text = "Primary clicked!"; - - var successBtn = new Button { Text = "Success", BackgroundColor = Color.FromArgb("#4CAF50"), TextColor = Colors.White }; - successBtn.Clicked += (s, e) => resultLabel.Text = "Success clicked!"; - - var dangerBtn = new Button { Text = "Danger", BackgroundColor = Color.FromArgb("#F44336"), TextColor = Colors.White }; - dangerBtn.Clicked += (s, e) => resultLabel.Text = "Danger clicked!"; - - buttonRow.Children.Add(primaryBtn); - buttonRow.Children.Add(successBtn); - buttonRow.Children.Add(dangerBtn); - - layout.Children.Add(buttonRow); - layout.Children.Add(resultLabel); - - return layout; - } - - private View CreateCheckBoxRow() - { - var layout = new HorizontalStackLayout { Spacing = 20 }; - - var cb1 = new CheckBox { IsChecked = true }; - var cb2 = new CheckBox { IsChecked = false }; - - layout.Children.Add(cb1); - layout.Children.Add(new Label { Text = "Option 1", VerticalOptions = LayoutOptions.Center }); - layout.Children.Add(cb2); - layout.Children.Add(new Label { Text = "Option 2", VerticalOptions = LayoutOptions.Center }); - - return layout; - } - - private View CreateSwitchRow() - { - var label = new Label { Text = "Off", VerticalOptions = LayoutOptions.Center }; - var sw = new Switch { IsToggled = false }; - sw.Toggled += (s, e) => label.Text = e.Value ? "On" : "Off"; - - return new HorizontalStackLayout - { - Spacing = 10, - Children = { sw, label } - }; - } - - private View CreateSliderRow() - { - var label = new Label { Text = "Value: 50" }; - var slider = new Slider { Minimum = 0, Maximum = 100, Value = 50 }; - slider.ValueChanged += (s, e) => label.Text = $"Value: {(int)e.NewValue}"; - - return new VerticalStackLayout - { - Spacing = 5, - Children = { slider, label } - }; - } - - private View CreatePickerRow() - { - var label = new Label { Text = "Selected: (none)", TextColor = Colors.Gray }; - var picker = new Picker { Title = "Select a fruit" }; - picker.Items.Add("Apple"); - picker.Items.Add("Banana"); - picker.Items.Add("Cherry"); - picker.Items.Add("Date"); - picker.Items.Add("Elderberry"); - - picker.SelectedIndexChanged += (s, e) => - { - if (picker.SelectedIndex >= 0) - label.Text = $"Selected: {picker.Items[picker.SelectedIndex]}"; - }; - - return new VerticalStackLayout - { - Spacing = 5, - Children = { picker, label } - }; - } - - private View CreateProgressRow() - { - var progress = new ProgressBar { Progress = 0.7 }; - var activity = new ActivityIndicator { IsRunning = true }; - - return new VerticalStackLayout - { - Spacing = 10, - Children = - { - progress, - new Label { Text = "70% Complete", FontSize = 12, TextColor = Colors.Gray }, - new HorizontalStackLayout - { - Spacing = 10, - Children = - { - activity, - new Label { Text = "Loading...", VerticalOptions = LayoutOptions.Center, TextColor = Colors.Gray } - } - } - } - }; - } -} diff --git a/samples/ShellDemo/Pages/DetailPage.cs b/samples/ShellDemo/Pages/DetailPage.cs deleted file mode 100644 index 438751b..0000000 --- a/samples/ShellDemo/Pages/DetailPage.cs +++ /dev/null @@ -1,123 +0,0 @@ -// DetailPage - Demonstrates push/pop navigation - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; -using Microsoft.Maui.Platform.Linux.Hosting; - -namespace ShellDemo; - -/// -/// A detail page that can be pushed onto the navigation stack. -/// -public class DetailPage : ContentPage -{ - private readonly string _itemName; - - public DetailPage() : this("Detail Item") - { - } - - public DetailPage(string itemName) - { - _itemName = itemName; - Title = "Detail Page"; - - Content = new VerticalStackLayout - { - Padding = new Thickness(30), - Spacing = 20, - VerticalOptions = LayoutOptions.Center, - Children = - { - new Label - { - Text = "Pushed Page", - FontSize = 28, - FontAttributes = FontAttributes.Bold, - HorizontalOptions = LayoutOptions.Center, - TextColor = Color.FromArgb("#9C27B0") - }, - - new Label - { - Text = $"You navigated to: {_itemName}", - FontSize = 16, - HorizontalOptions = LayoutOptions.Center - }, - - new Label - { - Text = "This page was pushed onto the navigation stack using Shell.Current.GoToAsync()", - FontSize = 14, - TextColor = Colors.Gray, - HorizontalTextAlignment = TextAlignment.Center, - LineBreakMode = LineBreakMode.WordWrap - }, - - new BoxView - { - HeightRequest = 2, - Color = Color.FromArgb("#E0E0E0"), - Margin = new Thickness(0, 20) - }, - - CreateBackButton(), - - new Label - { - Text = "Use the back button above or the hardware/gesture back to pop this page", - FontSize = 12, - TextColor = Colors.Gray, - HorizontalTextAlignment = TextAlignment.Center, - Margin = new Thickness(0, 20, 0, 0) - } - } - }; - } - - private Button CreateBackButton() - { - var backBtn = new Button - { - Text = "Go Back (Pop)", - BackgroundColor = Color.FromArgb("#9C27B0"), - TextColor = Colors.White, - HorizontalOptions = LayoutOptions.Center, - Padding = new Thickness(30, 10) - }; - - backBtn.Clicked += (s, e) => - { - // Pop this page off the navigation stack using LinuxViewRenderer - Console.WriteLine("[DetailPage] Go Back clicked"); - var success = LinuxViewRenderer.PopPage(); - Console.WriteLine($"[DetailPage] PopPage result: {success}"); - }; - - return backBtn; - } -} - -/// -/// Query property for passing data to DetailPage. -/// -[QueryProperty(nameof(ItemName), "item")] -public class DetailPageWithQuery : DetailPage -{ - private string _itemName = "Item"; - - public string ItemName - { - get => _itemName; - set - { - _itemName = value; - // Update the title when the property is set - Title = $"Detail: {value}"; - } - } - - public DetailPageWithQuery() : base() - { - } -} diff --git a/samples/ShellDemo/Pages/GridsPage.cs b/samples/ShellDemo/Pages/GridsPage.cs deleted file mode 100644 index 09cea44..0000000 --- a/samples/ShellDemo/Pages/GridsPage.cs +++ /dev/null @@ -1,594 +0,0 @@ -// GridsPage - Demonstrates Grid layouts with various options - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class GridsPage : ContentPage -{ - public GridsPage() - { - Title = "Grids"; - - Content = new ScrollView - { - Orientation = ScrollOrientation.Both, - Content = new VerticalStackLayout - { - Spacing = 25, - Children = - { - CreateSectionHeader("Basic Grid (2x2)"), - CreateBasicGrid(), - - CreateSectionHeader("Column Definitions"), - CreateColumnDefinitionsDemo(), - - CreateSectionHeader("Row Definitions"), - CreateRowDefinitionsDemo(), - - CreateSectionHeader("Auto Rows (Empty vs Content)"), - CreateAutoRowsDemo(), - - CreateSectionHeader("Star Sizing (Proportional)"), - CreateStarSizingDemo(), - - CreateSectionHeader("Row & Column Spacing"), - CreateSpacingDemo(), - - CreateSectionHeader("Row & Column Span"), - CreateSpanDemo(), - - CreateSectionHeader("Mixed Sizing"), - CreateMixedSizingDemo(), - - CreateSectionHeader("Nested Grids"), - CreateNestedGridDemo(), - - new BoxView { HeightRequest = 20 } // Bottom padding - } - } - }; - } - - private Label CreateSectionHeader(string text) - { - return new Label - { - Text = text, - FontSize = 18, - FontAttributes = FontAttributes.Bold, - TextColor = Color.FromArgb("#2196F3"), - Margin = new Thickness(0, 10, 0, 5) - }; - } - - private View CreateBasicGrid() - { - var grid = new Grid - { - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - }, - BackgroundColor = Color.FromArgb("#F5F5F5") - }; - - var cell1 = CreateCell("Row 0, Col 0", "#E3F2FD"); - var cell2 = CreateCell("Row 0, Col 1", "#E8F5E9"); - var cell3 = CreateCell("Row 1, Col 0", "#FFF3E0"); - var cell4 = CreateCell("Row 1, Col 1", "#FCE4EC"); - - Grid.SetRow(cell1, 0); Grid.SetColumn(cell1, 0); - Grid.SetRow(cell2, 0); Grid.SetColumn(cell2, 1); - Grid.SetRow(cell3, 1); Grid.SetColumn(cell3, 0); - Grid.SetRow(cell4, 1); Grid.SetColumn(cell4, 1); - - grid.Children.Add(cell1); - grid.Children.Add(cell2); - grid.Children.Add(cell3); - grid.Children.Add(cell4); - - return CreateDemoContainer(grid, "Equal columns using Star sizing"); - } - - private View CreateColumnDefinitionsDemo() - { - var stack = new VerticalStackLayout { Spacing = 15 }; - - // Auto width columns - var autoGrid = new Grid - { - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Auto }, - new ColumnDefinition { Width = GridLength.Auto }, - new ColumnDefinition { Width = GridLength.Auto } - }, - BackgroundColor = Color.FromArgb("#F5F5F5") - }; - - var a1 = CreateCell("Auto", "#BBDEFB"); - var a2 = CreateCell("Auto Width", "#C8E6C9"); - var a3 = CreateCell("A", "#FFECB3"); - Grid.SetColumn(a1, 0); - Grid.SetColumn(a2, 1); - Grid.SetColumn(a3, 2); - autoGrid.Children.Add(a1); - autoGrid.Children.Add(a2); - autoGrid.Children.Add(a3); - - stack.Children.Add(new Label { Text = "Auto: Sizes to content", FontSize = 12, TextColor = Colors.Gray }); - stack.Children.Add(autoGrid); - - // Absolute width columns - var absoluteGrid = new Grid - { - ColumnDefinitions = - { - new ColumnDefinition { Width = new GridLength(50) }, - new ColumnDefinition { Width = new GridLength(100) }, - new ColumnDefinition { Width = new GridLength(150) } - }, - BackgroundColor = Color.FromArgb("#F5F5F5") - }; - - var b1 = CreateCell("50px", "#BBDEFB"); - var b2 = CreateCell("100px", "#C8E6C9"); - var b3 = CreateCell("150px", "#FFECB3"); - Grid.SetColumn(b1, 0); - Grid.SetColumn(b2, 1); - Grid.SetColumn(b3, 2); - absoluteGrid.Children.Add(b1); - absoluteGrid.Children.Add(b2); - absoluteGrid.Children.Add(b3); - - stack.Children.Add(new Label { Text = "Absolute: Fixed pixel widths (50, 100, 150)", FontSize = 12, TextColor = Colors.Gray, Margin = new Thickness(0, 10, 0, 0) }); - stack.Children.Add(absoluteGrid); - - return stack; - } - - private View CreateRowDefinitionsDemo() - { - var grid = new Grid - { - WidthRequest = 200, - RowDefinitions = - { - new RowDefinition { Height = new GridLength(30) }, - new RowDefinition { Height = new GridLength(50) }, - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = new GridLength(40) } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star } - }, - BackgroundColor = Color.FromArgb("#F5F5F5") - }; - - var r1 = CreateCell("30px height", "#BBDEFB"); - var r2 = CreateCell("50px height", "#C8E6C9"); - var r3 = CreateCell("Auto height\n(fits content)", "#FFECB3"); - var r4 = CreateCell("40px height", "#F8BBD9"); - - Grid.SetRow(r1, 0); - Grid.SetRow(r2, 1); - Grid.SetRow(r3, 2); - Grid.SetRow(r4, 3); - - grid.Children.Add(r1); - grid.Children.Add(r2); - grid.Children.Add(r3); - grid.Children.Add(r4); - - return CreateDemoContainer(grid, "Different row heights: 30px, 50px, Auto, 40px"); - } - - private View CreateAutoRowsDemo() - { - var stack = new VerticalStackLayout { Spacing = 15 }; - - // Grid with empty Auto row - var emptyAutoGrid = new Grid - { - WidthRequest = 250, - RowDefinitions = - { - new RowDefinition { Height = new GridLength(40) }, - new RowDefinition { Height = GridLength.Auto }, // Empty - should collapse - new RowDefinition { Height = new GridLength(40) } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star } - }, - BackgroundColor = Color.FromArgb("#E0E0E0") - }; - - var r1 = CreateCell("Row 0: 40px", "#BBDEFB"); - // Row 1 is Auto with NO content - should be 0 height - var r3 = CreateCell("Row 2: 40px", "#C8E6C9"); - - Grid.SetRow(r1, 0); - Grid.SetRow(r3, 2); // Skip row 1 - - emptyAutoGrid.Children.Add(r1); - emptyAutoGrid.Children.Add(r3); - - stack.Children.Add(new Label { Text = "Empty Auto row (Row 1) should collapse to 0 height:", FontSize = 12, TextColor = Colors.Gray }); - stack.Children.Add(emptyAutoGrid); - - // Grid with Auto row that has content - var contentAutoGrid = new Grid - { - WidthRequest = 250, - RowDefinitions = - { - new RowDefinition { Height = new GridLength(40) }, - new RowDefinition { Height = GridLength.Auto }, // Has content - new RowDefinition { Height = new GridLength(40) } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star } - }, - BackgroundColor = Color.FromArgb("#E0E0E0") - }; - - var c1 = CreateCell("Row 0: 40px", "#BBDEFB"); - var c2 = CreateCell("Row 1: Auto (sized to this content)", "#FFECB3"); - var c3 = CreateCell("Row 2: 40px", "#C8E6C9"); - - Grid.SetRow(c1, 0); - Grid.SetRow(c2, 1); - Grid.SetRow(c3, 2); - - contentAutoGrid.Children.Add(c1); - contentAutoGrid.Children.Add(c2); - contentAutoGrid.Children.Add(c3); - - stack.Children.Add(new Label { Text = "Auto row with content sizes to fit:", FontSize = 12, TextColor = Colors.Gray, Margin = new Thickness(0, 10, 0, 0) }); - stack.Children.Add(contentAutoGrid); - - return stack; - } - - private View CreateStarSizingDemo() - { - var grid = new Grid - { - ColumnDefinitions = - { - new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }, - new ColumnDefinition { Width = new GridLength(2, GridUnitType.Star) }, - new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } - }, - BackgroundColor = Color.FromArgb("#F5F5F5") - }; - - var s1 = CreateCell("1*", "#BBDEFB"); - var s2 = CreateCell("2* (double)", "#C8E6C9"); - var s3 = CreateCell("1*", "#FFECB3"); - - Grid.SetColumn(s1, 0); - Grid.SetColumn(s2, 1); - Grid.SetColumn(s3, 2); - - grid.Children.Add(s1); - grid.Children.Add(s2); - grid.Children.Add(s3); - - return CreateDemoContainer(grid, "Star proportions: 1* | 2* | 1* = 25% | 50% | 25%"); - } - - private View CreateSpacingDemo() - { - var stack = new VerticalStackLayout { Spacing = 15 }; - - // No spacing - var noSpacing = new Grid - { - RowSpacing = 0, - ColumnSpacing = 0, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - } - }; - AddFourCells(noSpacing); - stack.Children.Add(new Label { Text = "No spacing (RowSpacing=0, ColumnSpacing=0)", FontSize = 12, TextColor = Colors.Gray }); - stack.Children.Add(noSpacing); - - // With spacing - var withSpacing = new Grid - { - RowSpacing = 10, - ColumnSpacing = 10, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - } - }; - AddFourCells(withSpacing); - stack.Children.Add(new Label { Text = "With spacing (RowSpacing=10, ColumnSpacing=10)", FontSize = 12, TextColor = Colors.Gray, Margin = new Thickness(0, 10, 0, 0) }); - stack.Children.Add(withSpacing); - - // Different row/column spacing - var mixedSpacing = new Grid - { - RowSpacing = 5, - ColumnSpacing = 20, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - } - }; - AddFourCells(mixedSpacing); - stack.Children.Add(new Label { Text = "Mixed spacing (RowSpacing=5, ColumnSpacing=20)", FontSize = 12, TextColor = Colors.Gray, Margin = new Thickness(0, 10, 0, 0) }); - stack.Children.Add(mixedSpacing); - - return stack; - } - - private View CreateSpanDemo() - { - var grid = new Grid - { - RowSpacing = 5, - ColumnSpacing = 5, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - } - }; - - // Spanning header - var header = CreateCell("ColumnSpan=3 (Header)", "#1976D2", Colors.White); - Grid.SetRow(header, 0); - Grid.SetColumn(header, 0); - Grid.SetColumnSpan(header, 3); - - // Left sidebar spanning 2 rows - var sidebar = CreateCell("RowSpan=2\n(Sidebar)", "#388E3C", Colors.White); - Grid.SetRow(sidebar, 1); - Grid.SetColumn(sidebar, 0); - Grid.SetRowSpan(sidebar, 2); - - // Content cells - var content1 = CreateCell("Content 1", "#E3F2FD"); - Grid.SetRow(content1, 1); - Grid.SetColumn(content1, 1); - - var content2 = CreateCell("Content 2", "#E8F5E9"); - Grid.SetRow(content2, 1); - Grid.SetColumn(content2, 2); - - var content3 = CreateCell("Content 3", "#FFF3E0"); - Grid.SetRow(content3, 2); - Grid.SetColumn(content3, 1); - - var content4 = CreateCell("Content 4", "#FCE4EC"); - Grid.SetRow(content4, 2); - Grid.SetColumn(content4, 2); - - grid.Children.Add(header); - grid.Children.Add(sidebar); - grid.Children.Add(content1); - grid.Children.Add(content2); - grid.Children.Add(content3); - grid.Children.Add(content4); - - return CreateDemoContainer(grid, "Header spans 3 columns, Sidebar spans 2 rows"); - } - - private View CreateMixedSizingDemo() - { - var grid = new Grid - { - ColumnSpacing = 5, - ColumnDefinitions = - { - new ColumnDefinition { Width = new GridLength(60) }, // Fixed - new ColumnDefinition { Width = GridLength.Star }, // Fill - new ColumnDefinition { Width = GridLength.Auto }, // Auto - new ColumnDefinition { Width = new GridLength(60) } // Fixed - }, - BackgroundColor = Color.FromArgb("#F5F5F5") - }; - - var c1 = CreateCell("60px", "#BBDEFB"); - var c2 = CreateCell("Star (fills remaining)", "#C8E6C9"); - var c3 = CreateCell("Auto", "#FFECB3"); - var c4 = CreateCell("60px", "#F8BBD9"); - - Grid.SetColumn(c1, 0); - Grid.SetColumn(c2, 1); - Grid.SetColumn(c3, 2); - Grid.SetColumn(c4, 3); - - grid.Children.Add(c1); - grid.Children.Add(c2); - grid.Children.Add(c3); - grid.Children.Add(c4); - - return CreateDemoContainer(grid, "Mixed: 60px | Star | Auto | 60px"); - } - - private View CreateNestedGridDemo() - { - var outerGrid = new Grid - { - RowSpacing = 10, - ColumnSpacing = 10, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - }, - BackgroundColor = Color.FromArgb("#E0E0E0"), - Padding = new Thickness(10) - }; - - // Nested grid 1 - var innerGrid1 = new Grid - { - RowSpacing = 2, - ColumnSpacing = 2, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - } - }; - var i1a = CreateCell("A", "#BBDEFB", null, 8); - var i1b = CreateCell("B", "#90CAF9", null, 8); - var i1c = CreateCell("C", "#64B5F6", null, 8); - var i1d = CreateCell("D", "#42A5F5", null, 8); - Grid.SetRow(i1a, 0); Grid.SetColumn(i1a, 0); - Grid.SetRow(i1b, 0); Grid.SetColumn(i1b, 1); - Grid.SetRow(i1c, 1); Grid.SetColumn(i1c, 0); - Grid.SetRow(i1d, 1); Grid.SetColumn(i1d, 1); - innerGrid1.Children.Add(i1a); - innerGrid1.Children.Add(i1b); - innerGrid1.Children.Add(i1c); - innerGrid1.Children.Add(i1d); - - // Nested grid 2 - var innerGrid2 = new Grid - { - RowSpacing = 2, - ColumnSpacing = 2, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnDefinitions = - { - new ColumnDefinition { Width = GridLength.Star }, - new ColumnDefinition { Width = GridLength.Star } - } - }; - var i2a = CreateCell("1", "#C8E6C9", null, 8); - var i2b = CreateCell("2", "#A5D6A7", null, 8); - var i2c = CreateCell("3", "#81C784", null, 8); - var i2d = CreateCell("4", "#66BB6A", null, 8); - Grid.SetRow(i2a, 0); Grid.SetColumn(i2a, 0); - Grid.SetRow(i2b, 0); Grid.SetColumn(i2b, 1); - Grid.SetRow(i2c, 1); Grid.SetColumn(i2c, 0); - Grid.SetRow(i2d, 1); Grid.SetColumn(i2d, 1); - innerGrid2.Children.Add(i2a); - innerGrid2.Children.Add(i2b); - innerGrid2.Children.Add(i2c); - innerGrid2.Children.Add(i2d); - - Grid.SetRow(innerGrid1, 0); Grid.SetColumn(innerGrid1, 0); - Grid.SetRow(innerGrid2, 0); Grid.SetColumn(innerGrid2, 1); - - var label1 = new Label { Text = "Outer Grid Row 1", HorizontalOptions = LayoutOptions.Center }; - var label2 = new Label { Text = "Spans both columns", HorizontalOptions = LayoutOptions.Center }; - Grid.SetRow(label1, 1); Grid.SetColumn(label1, 0); - Grid.SetRow(label2, 1); Grid.SetColumn(label2, 1); - - outerGrid.Children.Add(innerGrid1); - outerGrid.Children.Add(innerGrid2); - outerGrid.Children.Add(label1); - outerGrid.Children.Add(label2); - - return CreateDemoContainer(outerGrid, "Outer grid contains two nested 2x2 grids"); - } - - private Border CreateCell(string text, string bgColor, Color? textColor = null, float fontSize = 12) - { - return new Border - { - BackgroundColor = Color.FromArgb(bgColor), - Padding = new Thickness(10, 8), - StrokeThickness = 0, - Content = new Label - { - Text = text, - FontSize = fontSize, - TextColor = textColor ?? Colors.Black, - HorizontalTextAlignment = TextAlignment.Center, - VerticalTextAlignment = TextAlignment.Center - } - }; - } - - private void AddFourCells(Grid grid) - { - var c1 = CreateCell("0,0", "#BBDEFB"); - var c2 = CreateCell("0,1", "#C8E6C9"); - var c3 = CreateCell("1,0", "#FFECB3"); - var c4 = CreateCell("1,1", "#F8BBD9"); - - Grid.SetRow(c1, 0); Grid.SetColumn(c1, 0); - Grid.SetRow(c2, 0); Grid.SetColumn(c2, 1); - Grid.SetRow(c3, 1); Grid.SetColumn(c3, 0); - Grid.SetRow(c4, 1); Grid.SetColumn(c4, 1); - - grid.Children.Add(c1); - grid.Children.Add(c2); - grid.Children.Add(c3); - grid.Children.Add(c4); - } - - private View CreateDemoContainer(View content, string description) - { - return new VerticalStackLayout - { - Spacing = 5, - Children = - { - new Label { Text = description, FontSize = 12, TextColor = Colors.Gray }, - content - } - }; - } -} diff --git a/samples/ShellDemo/Pages/HomePage.cs b/samples/ShellDemo/Pages/HomePage.cs deleted file mode 100644 index 9a39e63..0000000 --- a/samples/ShellDemo/Pages/HomePage.cs +++ /dev/null @@ -1,265 +0,0 @@ -// HomePage - Welcome page for the demo - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; -using Microsoft.Maui.Platform.Linux.Hosting; - -namespace ShellDemo; - -public class HomePage : ContentPage -{ - public HomePage() - { - Title = "Home"; - - Content = new ScrollView - { - Orientation = ScrollOrientation.Both, // Enable horizontal scrolling when window is too narrow - Content = new VerticalStackLayout - { - Padding = new Thickness(30), - Spacing = 20, - Children = - { - new Label - { - Text = "OpenMaui Linux", - FontSize = 32, - FontAttributes = FontAttributes.Bold, - HorizontalOptions = LayoutOptions.Center, - TextColor = Color.FromArgb("#2196F3") - }, - - new Label - { - Text = "Controls Demo", - FontSize = 20, - HorizontalOptions = LayoutOptions.Center, - TextColor = Colors.Gray - }, - - new BoxView - { - HeightRequest = 2, - Color = Color.FromArgb("#E0E0E0"), - Margin = new Thickness(0, 10) - }, - - new Label - { - Text = "Welcome to the comprehensive controls demonstration for OpenMaui Linux. " + - "This app showcases all the major UI controls available in the framework.", - FontSize = 14, - LineBreakMode = LineBreakMode.WordWrap, - HorizontalTextAlignment = TextAlignment.Center - }, - - CreateFeatureSection(), - - new Label - { - Text = "Use the flyout menu (swipe from left or tap the hamburger icon) to navigate between different control demos.", - FontSize = 12, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap, - HorizontalTextAlignment = TextAlignment.Center, - Margin = new Thickness(0, 20, 0, 0) - }, - - CreateQuickLinksSection(), - - CreateNavigationDemoSection() - } - } - }; - } - - private View CreateFeatureSection() - { - var grid = new Grid - { - ColumnDefinitions = - { - new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }, - new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) } - }, - RowDefinitions = - { - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto }, - new RowDefinition { Height = GridLength.Auto } - }, - ColumnSpacing = 15, - RowSpacing = 15, - Margin = new Thickness(0, 20) - }; - - var features = new[] - { - ("Buttons", "Various button styles and events"), - ("Text Input", "Entry, Editor, SearchBar"), - ("Selection", "CheckBox, Switch, Slider"), - ("Pickers", "Picker, DatePicker, TimePicker"), - ("Lists", "CollectionView with selection"), - ("Progress", "ProgressBar, ActivityIndicator") - }; - - for (int i = 0; i < features.Length; i++) - { - var (title, desc) = features[i]; - var card = CreateFeatureCard(title, desc); - Grid.SetRow(card, i / 2); - Grid.SetColumn(card, i % 2); - grid.Children.Add(card); - } - - return grid; - } - - private Frame CreateFeatureCard(string title, string description) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - HasShadow = true, - Content = new VerticalStackLayout - { - Spacing = 5, - Children = - { - new Label - { - Text = title, - FontSize = 14, - FontAttributes = FontAttributes.Bold, - TextColor = Color.FromArgb("#2196F3") - }, - new Label - { - Text = description, - FontSize = 11, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap - } - } - } - }; - } - - private View CreateQuickLinksSection() - { - var layout = new VerticalStackLayout - { - Spacing = 10, - Margin = new Thickness(0, 20, 0, 0) - }; - - layout.Children.Add(new Label - { - Text = "Quick Actions", - FontSize = 16, - FontAttributes = FontAttributes.Bold, - HorizontalOptions = LayoutOptions.Center - }); - - var buttonRow = new HorizontalStackLayout - { - Spacing = 10, - HorizontalOptions = LayoutOptions.Center - }; - - var buttonsBtn = new Button - { - Text = "Try Buttons", - BackgroundColor = Color.FromArgb("#2196F3"), - TextColor = Colors.White - }; - buttonsBtn.Clicked += (s, e) => LinuxViewRenderer.NavigateToRoute("Buttons"); - - var listsBtn = new Button - { - Text = "Try Lists", - BackgroundColor = Color.FromArgb("#4CAF50"), - TextColor = Colors.White - }; - listsBtn.Clicked += (s, e) => LinuxViewRenderer.NavigateToRoute("Lists"); - - buttonRow.Children.Add(buttonsBtn); - buttonRow.Children.Add(listsBtn); - layout.Children.Add(buttonRow); - - return layout; - } - - private View CreateNavigationDemoSection() - { - var frame = new Frame - { - CornerRadius = 8, - Padding = new Thickness(20), - BackgroundColor = Color.FromArgb("#F3E5F5"), - Margin = new Thickness(0, 20, 0, 0), - Content = new VerticalStackLayout - { - Spacing = 15, - Children = - { - new Label - { - Text = "Navigation Stack Demo", - FontSize = 18, - FontAttributes = FontAttributes.Bold, - TextColor = Color.FromArgb("#9C27B0"), - HorizontalOptions = LayoutOptions.Center - }, - - new Label - { - Text = "Demonstrate push/pop navigation using Shell.GoToAsync()", - FontSize = 12, - TextColor = Colors.Gray, - HorizontalTextAlignment = TextAlignment.Center - }, - - CreatePushButton("Push Detail Page", "detail"), - - new Label - { - Text = "Click the button to push a new page onto the navigation stack. " + - "Use the back button or 'Go Back' to pop it off.", - FontSize = 11, - TextColor = Colors.Gray, - HorizontalTextAlignment = TextAlignment.Center, - LineBreakMode = LineBreakMode.WordWrap - } - } - } - }; - - return frame; - } - - private Button CreatePushButton(string text, string route) - { - var btn = new Button - { - Text = text, - BackgroundColor = Color.FromArgb("#9C27B0"), - TextColor = Colors.White, - HorizontalOptions = LayoutOptions.Center, - Padding = new Thickness(30, 10) - }; - - btn.Clicked += (s, e) => - { - Console.WriteLine($"[HomePage] Push button clicked, navigating to {route}"); - // Use LinuxViewRenderer.PushPage for Skia-based navigation - var success = LinuxViewRenderer.PushPage(new DetailPage()); - Console.WriteLine($"[HomePage] PushPage result: {success}"); - }; - - return btn; - } -} diff --git a/samples/ShellDemo/Pages/ListsPage.cs b/samples/ShellDemo/Pages/ListsPage.cs deleted file mode 100644 index 1d93a67..0000000 --- a/samples/ShellDemo/Pages/ListsPage.cs +++ /dev/null @@ -1,249 +0,0 @@ -// ListsPage - CollectionView and ListView Demo - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class ListsPage : ContentPage -{ - private readonly Label _eventLog; - private int _eventCount = 0; - - public ListsPage() - { - Title = "Lists"; - - _eventLog = new Label - { - Text = "Events will appear here...", - FontSize = 11, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap - }; - - Content = new Grid - { - RowDefinitions = - { - new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, - new RowDefinition { Height = new GridLength(120) } - }, - Children = - { - CreateMainContent(), - CreateEventLogPanel() - } - }; - - Grid.SetRow((View)((Grid)Content).Children[0], 0); - Grid.SetRow((View)((Grid)Content).Children[1], 1); - } - - private View CreateMainContent() - { - return new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 20, - Children = - { - new Label { Text = "List Controls", FontSize = 24, FontAttributes = FontAttributes.Bold }, - - CreateSection("CollectionView - Fruits", CreateFruitsCollectionView()), - CreateSection("CollectionView - Colors", CreateColorsCollectionView()), - CreateSection("CollectionView - Contacts", CreateContactsCollectionView()) - } - } - }; - } - - private View CreateFruitsCollectionView() - { - var layout = new VerticalStackLayout { Spacing = 10 }; - - var fruits = new List - { - "Apple", "Banana", "Cherry", "Date", "Elderberry", - "Fig", "Grape", "Honeydew", "Kiwi", "Lemon", - "Mango", "Nectarine", "Orange", "Papaya", "Quince" - }; - - var selectedLabel = new Label { Text = "Tap a fruit to select", TextColor = Colors.Gray }; - - var collectionView = new CollectionView - { - ItemsSource = fruits, - HeightRequest = 200, - SelectionMode = SelectionMode.Single, - BackgroundColor = Color.FromArgb("#FAFAFA") - }; - - collectionView.SelectionChanged += (s, e) => - { - if (e.CurrentSelection.Count > 0) - { - var item = e.CurrentSelection[0]?.ToString(); - selectedLabel.Text = $"Selected: {item}"; - LogEvent($"Fruit selected: {item}"); - } - }; - - layout.Children.Add(collectionView); - layout.Children.Add(selectedLabel); - - return layout; - } - - private View CreateColorsCollectionView() - { - var layout = new VerticalStackLayout { Spacing = 10 }; - - var colors = new List - { - new("Red", "#F44336"), - new("Pink", "#E91E63"), - new("Purple", "#9C27B0"), - new("Deep Purple", "#673AB7"), - new("Indigo", "#3F51B5"), - new("Blue", "#2196F3"), - new("Cyan", "#00BCD4"), - new("Teal", "#009688"), - new("Green", "#4CAF50"), - new("Light Green", "#8BC34A"), - new("Lime", "#CDDC39"), - new("Yellow", "#FFEB3B"), - new("Amber", "#FFC107"), - new("Orange", "#FF9800"), - new("Deep Orange", "#FF5722") - }; - - var collectionView = new CollectionView - { - ItemsSource = colors, - HeightRequest = 180, - SelectionMode = SelectionMode.Single, - BackgroundColor = Colors.White - }; - - collectionView.SelectionChanged += (s, e) => - { - if (e.CurrentSelection.Count > 0 && e.CurrentSelection[0] is ColorItem item) - { - LogEvent($"Color selected: {item.Name} ({item.Hex})"); - } - }; - - layout.Children.Add(collectionView); - layout.Children.Add(new Label { Text = "Scroll to see all colors", FontSize = 11, TextColor = Colors.Gray }); - - return layout; - } - - private View CreateContactsCollectionView() - { - var layout = new VerticalStackLayout { Spacing = 10 }; - - var contacts = new List - { - new("Alice Johnson", "alice@example.com", "Engineering"), - new("Bob Smith", "bob@example.com", "Marketing"), - new("Carol Williams", "carol@example.com", "Design"), - new("David Brown", "david@example.com", "Sales"), - new("Eva Martinez", "eva@example.com", "Engineering"), - new("Frank Lee", "frank@example.com", "Support"), - new("Grace Kim", "grace@example.com", "HR"), - new("Henry Wilson", "henry@example.com", "Finance") - }; - - var collectionView = new CollectionView - { - ItemsSource = contacts, - HeightRequest = 200, - SelectionMode = SelectionMode.Single, - BackgroundColor = Colors.White - }; - - collectionView.SelectionChanged += (s, e) => - { - if (e.CurrentSelection.Count > 0 && e.CurrentSelection[0] is ContactItem contact) - { - LogEvent($"Contact: {contact.Name} - {contact.Department}"); - } - }; - - layout.Children.Add(collectionView); - - // Action buttons - var buttonRow = new HorizontalStackLayout { Spacing = 10 }; - var addBtn = new Button { Text = "Add Contact", BackgroundColor = Colors.Green, TextColor = Colors.White }; - addBtn.Clicked += (s, e) => LogEvent("Add contact clicked"); - var deleteBtn = new Button { Text = "Delete Selected", BackgroundColor = Colors.Red, TextColor = Colors.White }; - deleteBtn.Clicked += (s, e) => LogEvent("Delete contact clicked"); - buttonRow.Children.Add(addBtn); - buttonRow.Children.Add(deleteBtn); - layout.Children.Add(buttonRow); - - return layout; - } - - private Frame CreateSection(string title, View content) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - Content = new VerticalStackLayout - { - Spacing = 10, - Children = - { - new Label { Text = title, FontSize = 16, FontAttributes = FontAttributes.Bold }, - content - } - } - }; - } - - private View CreateEventLogPanel() - { - return new Frame - { - BackgroundColor = Color.FromArgb("#F5F5F5"), - Padding = new Thickness(10), - CornerRadius = 0, - Content = new VerticalStackLayout - { - Children = - { - new Label { Text = "Event Log:", FontSize = 12, FontAttributes = FontAttributes.Bold }, - new ScrollView - { - HeightRequest = 80, - Content = _eventLog - } - } - } - }; - } - - private void LogEvent(string message) - { - _eventCount++; - var timestamp = DateTime.Now.ToString("HH:mm:ss"); - _eventLog.Text = $"[{timestamp}] {_eventCount}. {message}\n{_eventLog.Text}"; - } -} - -public record ColorItem(string Name, string Hex) -{ - public override string ToString() => Name; -} - -public record ContactItem(string Name, string Email, string Department) -{ - public override string ToString() => $"{Name} ({Department})"; -} diff --git a/samples/ShellDemo/Pages/PickersPage.cs b/samples/ShellDemo/Pages/PickersPage.cs deleted file mode 100644 index b5ae1d9..0000000 --- a/samples/ShellDemo/Pages/PickersPage.cs +++ /dev/null @@ -1,261 +0,0 @@ -// PickersPage - Picker, DatePicker, TimePicker Demo - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class PickersPage : ContentPage -{ - private readonly Label _eventLog; - private int _eventCount = 0; - - public PickersPage() - { - Title = "Pickers"; - - _eventLog = new Label - { - Text = "Events will appear here...", - FontSize = 11, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap - }; - - Content = new Grid - { - RowDefinitions = - { - new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, - new RowDefinition { Height = new GridLength(120) } - }, - Children = - { - CreateMainContent(), - CreateEventLogPanel() - } - }; - - Grid.SetRow((View)((Grid)Content).Children[0], 0); - Grid.SetRow((View)((Grid)Content).Children[1], 1); - } - - private View CreateMainContent() - { - return new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 20, - Children = - { - new Label { Text = "Picker Controls", FontSize = 24, FontAttributes = FontAttributes.Bold }, - - CreateSection("Picker", CreatePickerDemo()), - CreateSection("DatePicker", CreateDatePickerDemo()), - CreateSection("TimePicker", CreateTimePickerDemo()) - } - } - }; - } - - private View CreatePickerDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Basic picker - var selectedLabel = new Label { Text = "Selected: (none)", TextColor = Colors.Gray }; - var picker1 = new Picker { Title = "Select a fruit" }; - picker1.Items.Add("Apple"); - picker1.Items.Add("Banana"); - picker1.Items.Add("Cherry"); - picker1.Items.Add("Date"); - picker1.Items.Add("Elderberry"); - picker1.Items.Add("Fig"); - picker1.Items.Add("Grape"); - picker1.SelectedIndexChanged += (s, e) => - { - if (picker1.SelectedIndex >= 0) - { - var item = picker1.Items[picker1.SelectedIndex]; - selectedLabel.Text = $"Selected: {item}"; - LogEvent($"Fruit selected: {item}"); - } - }; - layout.Children.Add(picker1); - layout.Children.Add(selectedLabel); - - // Picker with default selection - layout.Children.Add(new Label { Text = "With Default Selection:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var picker2 = new Picker { Title = "Select a color" }; - picker2.Items.Add("Red"); - picker2.Items.Add("Green"); - picker2.Items.Add("Blue"); - picker2.Items.Add("Yellow"); - picker2.Items.Add("Purple"); - picker2.SelectedIndex = 2; // Blue - picker2.SelectedIndexChanged += (s, e) => - { - if (picker2.SelectedIndex >= 0) - LogEvent($"Color selected: {picker2.Items[picker2.SelectedIndex]}"); - }; - layout.Children.Add(picker2); - - // Styled picker - layout.Children.Add(new Label { Text = "Styled Picker:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var picker3 = new Picker - { - Title = "Select size", - TextColor = Colors.DarkBlue, - TitleColor = Colors.Gray - }; - picker3.Items.Add("Small"); - picker3.Items.Add("Medium"); - picker3.Items.Add("Large"); - picker3.Items.Add("Extra Large"); - picker3.SelectedIndexChanged += (s, e) => - { - if (picker3.SelectedIndex >= 0) - LogEvent($"Size selected: {picker3.Items[picker3.SelectedIndex]}"); - }; - layout.Children.Add(picker3); - - return layout; - } - - private View CreateDatePickerDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Basic date picker - var dateLabel = new Label { Text = $"Selected: {DateTime.Today:d}" }; - var datePicker1 = new DatePicker { Date = DateTime.Today }; - datePicker1.DateSelected += (s, e) => - { - dateLabel.Text = $"Selected: {e.NewDate:d}"; - LogEvent($"Date selected: {e.NewDate:d}"); - }; - layout.Children.Add(datePicker1); - layout.Children.Add(dateLabel); - - // Date picker with range - layout.Children.Add(new Label { Text = "With Date Range (this month only):", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var startOfMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); - var endOfMonth = startOfMonth.AddMonths(1).AddDays(-1); - var datePicker2 = new DatePicker - { - MinimumDate = startOfMonth, - MaximumDate = endOfMonth, - Date = DateTime.Today - }; - datePicker2.DateSelected += (s, e) => LogEvent($"Date (limited): {e.NewDate:d}"); - layout.Children.Add(datePicker2); - - // Styled date picker - layout.Children.Add(new Label { Text = "Styled DatePicker:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var datePicker3 = new DatePicker - { - Date = DateTime.Today.AddDays(7), - TextColor = Colors.DarkGreen - }; - datePicker3.DateSelected += (s, e) => LogEvent($"Styled date: {e.NewDate:d}"); - layout.Children.Add(datePicker3); - - return layout; - } - - private View CreateTimePickerDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Basic time picker - var timeLabel = new Label { Text = $"Selected: {DateTime.Now:t}" }; - var timePicker1 = new TimePicker { Time = DateTime.Now.TimeOfDay }; - timePicker1.PropertyChanged += (s, e) => - { - if (e.PropertyName == nameof(TimePicker.Time)) - { - var time = timePicker1.Time; - timeLabel.Text = $"Selected: {time:hh\\:mm}"; - LogEvent($"Time selected: {time:hh\\:mm}"); - } - }; - layout.Children.Add(timePicker1); - layout.Children.Add(timeLabel); - - // Styled time picker - layout.Children.Add(new Label { Text = "Styled TimePicker:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var timePicker2 = new TimePicker - { - Time = new TimeSpan(14, 30, 0), - TextColor = Colors.DarkBlue - }; - timePicker2.PropertyChanged += (s, e) => - { - if (e.PropertyName == nameof(TimePicker.Time)) - LogEvent($"Styled time: {timePicker2.Time:hh\\:mm}"); - }; - layout.Children.Add(timePicker2); - - // Morning alarm example - layout.Children.Add(new Label { Text = "Alarm Time:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var alarmRow = new HorizontalStackLayout { Spacing = 10 }; - var alarmPicker = new TimePicker { Time = new TimeSpan(7, 0, 0) }; - var alarmBtn = new Button { Text = "Set Alarm", BackgroundColor = Colors.Orange, TextColor = Colors.White }; - alarmBtn.Clicked += (s, e) => LogEvent($"Alarm set for {alarmPicker.Time:hh\\:mm}"); - alarmRow.Children.Add(alarmPicker); - alarmRow.Children.Add(alarmBtn); - layout.Children.Add(alarmRow); - - return layout; - } - - private Frame CreateSection(string title, View content) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - Content = new VerticalStackLayout - { - Spacing = 10, - Children = - { - new Label { Text = title, FontSize = 16, FontAttributes = FontAttributes.Bold }, - content - } - } - }; - } - - private View CreateEventLogPanel() - { - return new Frame - { - BackgroundColor = Color.FromArgb("#F5F5F5"), - Padding = new Thickness(10), - CornerRadius = 0, - Content = new VerticalStackLayout - { - Children = - { - new Label { Text = "Event Log:", FontSize = 12, FontAttributes = FontAttributes.Bold }, - new ScrollView - { - HeightRequest = 80, - Content = _eventLog - } - } - } - }; - } - - private void LogEvent(string message) - { - _eventCount++; - var timestamp = DateTime.Now.ToString("HH:mm:ss"); - _eventLog.Text = $"[{timestamp}] {_eventCount}. {message}\n{_eventLog.Text}"; - } -} diff --git a/samples/ShellDemo/Pages/ProgressPage.cs b/samples/ShellDemo/Pages/ProgressPage.cs deleted file mode 100644 index 87e4828..0000000 --- a/samples/ShellDemo/Pages/ProgressPage.cs +++ /dev/null @@ -1,261 +0,0 @@ -// ProgressPage - ProgressBar and ActivityIndicator Demo - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class ProgressPage : ContentPage -{ - private readonly Label _eventLog; - private int _eventCount = 0; - private ProgressBar? _animatedProgress; - private bool _isAnimating = false; - - public ProgressPage() - { - Title = "Progress"; - - _eventLog = new Label - { - Text = "Events will appear here...", - FontSize = 11, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap - }; - - Content = new Grid - { - RowDefinitions = - { - new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, - new RowDefinition { Height = new GridLength(120) } - }, - Children = - { - CreateMainContent(), - CreateEventLogPanel() - } - }; - - Grid.SetRow((View)((Grid)Content).Children[0], 0); - Grid.SetRow((View)((Grid)Content).Children[1], 1); - } - - private View CreateMainContent() - { - return new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 20, - Children = - { - new Label { Text = "Progress Indicators", FontSize = 24, FontAttributes = FontAttributes.Bold }, - - CreateSection("ProgressBar", CreateProgressBarDemo()), - CreateSection("ActivityIndicator", CreateActivityIndicatorDemo()), - CreateSection("Interactive Demo", CreateInteractiveDemo()) - } - } - }; - } - - private View CreateProgressBarDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Various progress values - var values = new[] { 0.0, 0.25, 0.5, 0.75, 1.0 }; - foreach (var value in values) - { - var row = new HorizontalStackLayout { Spacing = 10 }; - var progress = new ProgressBar { Progress = value, WidthRequest = 200 }; - var label = new Label { Text = $"{value * 100:0}%", VerticalOptions = LayoutOptions.Center, WidthRequest = 50 }; - row.Children.Add(progress); - row.Children.Add(label); - layout.Children.Add(row); - } - - // Colored progress bars - layout.Children.Add(new Label { Text = "Colored Progress Bars:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - - var colors = new[] { Colors.Red, Colors.Green, Colors.Blue, Colors.Orange, Colors.Purple }; - foreach (var color in colors) - { - var progress = new ProgressBar { Progress = 0.7, ProgressColor = color }; - layout.Children.Add(progress); - } - - return layout; - } - - private View CreateActivityIndicatorDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Running indicator - var runningRow = new HorizontalStackLayout { Spacing = 15 }; - var runningIndicator = new ActivityIndicator { IsRunning = true }; - runningRow.Children.Add(runningIndicator); - runningRow.Children.Add(new Label { Text = "Loading...", VerticalOptions = LayoutOptions.Center }); - layout.Children.Add(runningRow); - - // Toggle indicator - var toggleRow = new HorizontalStackLayout { Spacing = 15 }; - var toggleIndicator = new ActivityIndicator { IsRunning = false }; - var toggleBtn = new Button { Text = "Start/Stop" }; - toggleBtn.Clicked += (s, e) => - { - toggleIndicator.IsRunning = !toggleIndicator.IsRunning; - LogEvent($"ActivityIndicator: {(toggleIndicator.IsRunning ? "Started" : "Stopped")}"); - }; - toggleRow.Children.Add(toggleIndicator); - toggleRow.Children.Add(toggleBtn); - layout.Children.Add(toggleRow); - - // Colored indicators - layout.Children.Add(new Label { Text = "Colored Indicators:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var colorRow = new HorizontalStackLayout { Spacing = 20 }; - var indicatorColors = new[] { Colors.Red, Colors.Green, Colors.Blue, Colors.Orange }; - foreach (var color in indicatorColors) - { - var indicator = new ActivityIndicator { IsRunning = true, Color = color }; - colorRow.Children.Add(indicator); - } - layout.Children.Add(colorRow); - - return layout; - } - - private View CreateInteractiveDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Slider-controlled progress - var progressLabel = new Label { Text = "Progress: 50%" }; - _animatedProgress = new ProgressBar { Progress = 0.5 }; - - var slider = new Slider { Minimum = 0, Maximum = 100, Value = 50 }; - slider.ValueChanged += (s, e) => - { - var value = e.NewValue / 100.0; - _animatedProgress.Progress = value; - progressLabel.Text = $"Progress: {e.NewValue:0}%"; - }; - - layout.Children.Add(_animatedProgress); - layout.Children.Add(slider); - layout.Children.Add(progressLabel); - - // Animated progress buttons - var buttonRow = new HorizontalStackLayout { Spacing = 10, Margin = new Thickness(0, 10, 0, 0) }; - - var resetBtn = new Button { Text = "Reset", BackgroundColor = Colors.Gray, TextColor = Colors.White }; - resetBtn.Clicked += async (s, e) => - { - _animatedProgress.Progress = 0; - slider.Value = 0; - LogEvent("Progress reset to 0%"); - }; - - var animateBtn = new Button { Text = "Animate to 100%", BackgroundColor = Colors.Blue, TextColor = Colors.White }; - animateBtn.Clicked += async (s, e) => - { - if (_isAnimating) return; - _isAnimating = true; - LogEvent("Animation started"); - - for (int i = (int)(slider.Value); i <= 100; i += 5) - { - _animatedProgress.Progress = i / 100.0; - slider.Value = i; - await Task.Delay(100); - } - - _isAnimating = false; - LogEvent("Animation completed"); - }; - - var simulateBtn = new Button { Text = "Simulate Download", BackgroundColor = Colors.Green, TextColor = Colors.White }; - simulateBtn.Clicked += async (s, e) => - { - if (_isAnimating) return; - _isAnimating = true; - LogEvent("Download simulation started"); - - _animatedProgress.Progress = 0; - slider.Value = 0; - - var random = new Random(); - double progress = 0; - while (progress < 1.0) - { - progress += random.NextDouble() * 0.1; - if (progress > 1.0) progress = 1.0; - _animatedProgress.Progress = progress; - slider.Value = progress * 100; - await Task.Delay(200 + random.Next(300)); - } - - _isAnimating = false; - LogEvent("Download simulation completed"); - }; - - buttonRow.Children.Add(resetBtn); - buttonRow.Children.Add(animateBtn); - buttonRow.Children.Add(simulateBtn); - layout.Children.Add(buttonRow); - - return layout; - } - - private Frame CreateSection(string title, View content) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - Content = new VerticalStackLayout - { - Spacing = 10, - Children = - { - new Label { Text = title, FontSize = 16, FontAttributes = FontAttributes.Bold }, - content - } - } - }; - } - - private View CreateEventLogPanel() - { - return new Frame - { - BackgroundColor = Color.FromArgb("#F5F5F5"), - Padding = new Thickness(10), - CornerRadius = 0, - Content = new VerticalStackLayout - { - Children = - { - new Label { Text = "Event Log:", FontSize = 12, FontAttributes = FontAttributes.Bold }, - new ScrollView - { - HeightRequest = 80, - Content = _eventLog - } - } - } - }; - } - - private void LogEvent(string message) - { - _eventCount++; - var timestamp = DateTime.Now.ToString("HH:mm:ss"); - _eventLog.Text = $"[{timestamp}] {_eventCount}. {message}\n{_eventLog.Text}"; - } -} diff --git a/samples/ShellDemo/Pages/SelectionPage.cs b/samples/ShellDemo/Pages/SelectionPage.cs deleted file mode 100644 index e247af6..0000000 --- a/samples/ShellDemo/Pages/SelectionPage.cs +++ /dev/null @@ -1,239 +0,0 @@ -// SelectionPage - CheckBox, Switch, Slider Demo - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class SelectionPage : ContentPage -{ - private readonly Label _eventLog; - private int _eventCount = 0; - - public SelectionPage() - { - Title = "Selection Controls"; - - _eventLog = new Label - { - Text = "Events will appear here...", - FontSize = 11, - TextColor = Colors.Gray, - LineBreakMode = LineBreakMode.WordWrap - }; - - Content = new Grid - { - RowDefinitions = - { - new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }, - new RowDefinition { Height = new GridLength(120) } - }, - Children = - { - CreateMainContent(), - CreateEventLogPanel() - } - }; - - Grid.SetRow((View)((Grid)Content).Children[0], 0); - Grid.SetRow((View)((Grid)Content).Children[1], 1); - } - - private View CreateMainContent() - { - return new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 20, - Children = - { - new Label { Text = "Selection Controls", FontSize = 24, FontAttributes = FontAttributes.Bold }, - - CreateSection("CheckBox", CreateCheckBoxDemo()), - CreateSection("Switch", CreateSwitchDemo()), - CreateSection("Slider", CreateSliderDemo()) - } - } - }; - } - - private View CreateCheckBoxDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Basic checkboxes - var basicRow = new HorizontalStackLayout { Spacing = 20 }; - - var cb1 = new CheckBox { IsChecked = false }; - cb1.CheckedChanged += (s, e) => LogEvent($"Checkbox 1: {(e.Value ? "Checked" : "Unchecked")}"); - basicRow.Children.Add(cb1); - basicRow.Children.Add(new Label { Text = "Option 1", VerticalOptions = LayoutOptions.Center }); - - var cb2 = new CheckBox { IsChecked = true }; - cb2.CheckedChanged += (s, e) => LogEvent($"Checkbox 2: {(e.Value ? "Checked" : "Unchecked")}"); - basicRow.Children.Add(cb2); - basicRow.Children.Add(new Label { Text = "Option 2 (default checked)", VerticalOptions = LayoutOptions.Center }); - - layout.Children.Add(basicRow); - - // Colored checkboxes - var colorRow = new HorizontalStackLayout { Spacing = 20 }; - var colors = new[] { Colors.Red, Colors.Green, Colors.Blue, Colors.Purple }; - foreach (var color in colors) - { - var cb = new CheckBox { Color = color, IsChecked = true }; - cb.CheckedChanged += (s, e) => LogEvent($"{color} checkbox: {(e.Value ? "Checked" : "Unchecked")}"); - colorRow.Children.Add(cb); - } - layout.Children.Add(new Label { Text = "Colored Checkboxes:", FontSize = 12 }); - layout.Children.Add(colorRow); - - // Disabled checkbox - var disabledRow = new HorizontalStackLayout { Spacing = 10 }; - var disabledCb = new CheckBox { IsChecked = true, IsEnabled = false }; - disabledRow.Children.Add(disabledCb); - disabledRow.Children.Add(new Label { Text = "Disabled (checked)", VerticalOptions = LayoutOptions.Center, TextColor = Colors.Gray }); - layout.Children.Add(disabledRow); - - return layout; - } - - private View CreateSwitchDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Basic switch - var basicRow = new HorizontalStackLayout { Spacing = 15 }; - var statusLabel = new Label { Text = "Off", VerticalOptions = LayoutOptions.Center, WidthRequest = 50 }; - var sw1 = new Switch { IsToggled = false }; - sw1.Toggled += (s, e) => - { - statusLabel.Text = e.Value ? "On" : "Off"; - LogEvent($"Switch toggled: {(e.Value ? "ON" : "OFF")}"); - }; - basicRow.Children.Add(sw1); - basicRow.Children.Add(statusLabel); - layout.Children.Add(basicRow); - - // Colored switches - var colorRow = new HorizontalStackLayout { Spacing = 20 }; - var switchColors = new[] { Colors.Green, Colors.Orange, Colors.Purple }; - foreach (var color in switchColors) - { - var sw = new Switch { IsToggled = true, OnColor = color }; - sw.Toggled += (s, e) => LogEvent($"{color} switch: {(e.Value ? "ON" : "OFF")}"); - colorRow.Children.Add(sw); - } - layout.Children.Add(new Label { Text = "Colored Switches:", FontSize = 12 }); - layout.Children.Add(colorRow); - - // Disabled switch - var disabledRow = new HorizontalStackLayout { Spacing = 10 }; - var disabledSw = new Switch { IsToggled = true, IsEnabled = false }; - disabledRow.Children.Add(disabledSw); - disabledRow.Children.Add(new Label { Text = "Disabled (on)", VerticalOptions = LayoutOptions.Center, TextColor = Colors.Gray }); - layout.Children.Add(disabledRow); - - return layout; - } - - private View CreateSliderDemo() - { - var layout = new VerticalStackLayout { Spacing = 15 }; - - // Basic slider - var valueLabel = new Label { Text = "Value: 50" }; - var slider1 = new Slider { Minimum = 0, Maximum = 100, Value = 50 }; - slider1.ValueChanged += (s, e) => - { - valueLabel.Text = $"Value: {(int)e.NewValue}"; - LogEvent($"Slider value: {(int)e.NewValue}"); - }; - layout.Children.Add(slider1); - layout.Children.Add(valueLabel); - - // Slider with custom range - layout.Children.Add(new Label { Text = "Temperature (0-40°C):", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var tempLabel = new Label { Text = "20°C" }; - var tempSlider = new Slider { Minimum = 0, Maximum = 40, Value = 20 }; - tempSlider.ValueChanged += (s, e) => - { - tempLabel.Text = $"{(int)e.NewValue}°C"; - LogEvent($"Temperature: {(int)e.NewValue}°C"); - }; - layout.Children.Add(tempSlider); - layout.Children.Add(tempLabel); - - // Colored slider - layout.Children.Add(new Label { Text = "Colored Slider:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var colorSlider = new Slider - { - Minimum = 0, - Maximum = 100, - Value = 75, - MinimumTrackColor = Colors.Green, - MaximumTrackColor = Colors.LightGray, - ThumbColor = Colors.DarkGreen - }; - colorSlider.ValueChanged += (s, e) => LogEvent($"Colored slider: {(int)e.NewValue}"); - layout.Children.Add(colorSlider); - - // Disabled slider - layout.Children.Add(new Label { Text = "Disabled Slider:", FontSize = 12, Margin = new Thickness(0, 10, 0, 0) }); - var disabledSlider = new Slider { Minimum = 0, Maximum = 100, Value = 30, IsEnabled = false }; - layout.Children.Add(disabledSlider); - - return layout; - } - - private Frame CreateSection(string title, View content) - { - return new Frame - { - CornerRadius = 8, - Padding = new Thickness(15), - BackgroundColor = Colors.White, - Content = new VerticalStackLayout - { - Spacing = 10, - Children = - { - new Label { Text = title, FontSize = 16, FontAttributes = FontAttributes.Bold }, - content - } - } - }; - } - - private View CreateEventLogPanel() - { - return new Frame - { - BackgroundColor = Color.FromArgb("#F5F5F5"), - Padding = new Thickness(10), - CornerRadius = 0, - Content = new VerticalStackLayout - { - Children = - { - new Label { Text = "Event Log:", FontSize = 12, FontAttributes = FontAttributes.Bold }, - new ScrollView - { - HeightRequest = 80, - Content = _eventLog - } - } - } - }; - } - - private void LogEvent(string message) - { - _eventCount++; - var timestamp = DateTime.Now.ToString("HH:mm:ss"); - _eventLog.Text = $"[{timestamp}] {_eventCount}. {message}\n{_eventLog.Text}"; - } -} diff --git a/samples/ShellDemo/Pages/TextInputPage.cs b/samples/ShellDemo/Pages/TextInputPage.cs deleted file mode 100644 index 95c4e28..0000000 --- a/samples/ShellDemo/Pages/TextInputPage.cs +++ /dev/null @@ -1,166 +0,0 @@ -// TextInputPage - Demonstrates text input controls - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace ShellDemo; - -public class TextInputPage : ContentPage -{ - private Label _entryOutput; - private Label _searchOutput; - private Label _editorOutput; - - public TextInputPage() - { - Title = "Text Input"; - - _entryOutput = new Label { TextColor = Colors.Gray, FontSize = 12 }; - _searchOutput = new Label { TextColor = Colors.Gray, FontSize = 12 }; - _editorOutput = new Label { TextColor = Colors.Gray, FontSize = 12 }; - - Content = new ScrollView - { - Content = new VerticalStackLayout - { - Padding = new Thickness(20), - Spacing = 15, - Children = - { - new Label - { - Text = "Text Input Controls", - FontSize = 24, - FontAttributes = FontAttributes.Bold - }, - new Label - { - Text = "Click on any field and start typing. All keyboard input is handled by the framework.", - FontSize = 14, - TextColor = Colors.Gray - }, - - // Entry Section - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Label { Text = "Entry (Single Line)", FontSize = 18, FontAttributes = FontAttributes.Bold }, - CreateEntry("Enter your name...", e => _entryOutput.Text = $"You typed: {e.Text}"), - _entryOutput, - - CreateEntry("Enter your email...", null, Keyboard.Email), - new Label { Text = "Email keyboard type", FontSize = 12, TextColor = Colors.Gray }, - - CreatePasswordEntry("Enter password..."), - new Label { Text = "Password field (text hidden)", FontSize = 12, TextColor = Colors.Gray }, - - // SearchBar Section - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Label { Text = "SearchBar", FontSize = 18, FontAttributes = FontAttributes.Bold }, - CreateSearchBar(), - _searchOutput, - - // Editor Section - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Label { Text = "Editor (Multi-line)", FontSize = 18, FontAttributes = FontAttributes.Bold }, - CreateEditor(), - _editorOutput, - - // Instructions - new BoxView { HeightRequest = 1, Color = Colors.LightGray }, - new Frame - { - BackgroundColor = Color.FromArgb("#E3F2FD"), - CornerRadius = 8, - Padding = new Thickness(15), - Content = new VerticalStackLayout - { - Spacing = 5, - Children = - { - new Label - { - Text = "Keyboard Shortcuts", - FontAttributes = FontAttributes.Bold - }, - new Label { Text = "Ctrl+A: Select all" }, - new Label { Text = "Ctrl+C: Copy" }, - new Label { Text = "Ctrl+V: Paste" }, - new Label { Text = "Ctrl+X: Cut" }, - new Label { Text = "Home/End: Move to start/end" }, - new Label { Text = "Shift+Arrow: Select text" } - } - } - } - } - } - }; - } - - private Entry CreateEntry(string placeholder, Action? onTextChanged, Keyboard? keyboard = null) - { - var entry = new Entry - { - Placeholder = placeholder, - FontSize = 14 - }; - - if (keyboard != null) - { - entry.Keyboard = keyboard; - } - - if (onTextChanged != null) - { - entry.TextChanged += (s, e) => onTextChanged(entry); - } - - return entry; - } - - private Entry CreatePasswordEntry(string placeholder) - { - return new Entry - { - Placeholder = placeholder, - FontSize = 14, - IsPassword = true - }; - } - - private SearchBar CreateSearchBar() - { - var searchBar = new SearchBar - { - Placeholder = "Search for items..." - }; - - searchBar.TextChanged += (s, e) => - { - _searchOutput.Text = $"Searching: {e.NewTextValue}"; - }; - - searchBar.SearchButtonPressed += (s, e) => - { - _searchOutput.Text = $"Search submitted: {searchBar.Text}"; - }; - - return searchBar; - } - - private Editor CreateEditor() - { - var editor = new Editor - { - Placeholder = "Enter multiple lines of text here...\nPress Enter to create new lines.", - HeightRequest = 120, - FontSize = 14 - }; - - editor.TextChanged += (s, e) => - { - var lineCount = string.IsNullOrEmpty(e.NewTextValue) ? 0 : e.NewTextValue.Split('\n').Length; - _editorOutput.Text = $"Lines: {lineCount}, Characters: {e.NewTextValue?.Length ?? 0}"; - }; - - return editor; - } -} diff --git a/samples/ShellDemo/Platforms/Linux/Program.cs b/samples/ShellDemo/Platforms/Linux/Program.cs deleted file mode 100644 index 4330c0f..0000000 --- a/samples/ShellDemo/Platforms/Linux/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Platforms/Linux/Program.cs - Linux platform entry point -// Same pattern as Android's MainActivity or iOS's AppDelegate - -using Microsoft.Maui.Platform.Linux; -using Microsoft.Maui.Platform.Linux.Hosting; - -namespace ShellDemo; - -class Program -{ - static void Main(string[] args) - { - // Create the shared MAUI app - var app = MauiProgram.CreateMauiApp(); - - // Run on Linux platform - LinuxApplication.Run(app, args); - } -} diff --git a/samples/ShellDemo/README.md b/samples/ShellDemo/README.md deleted file mode 100644 index b734932..0000000 --- a/samples/ShellDemo/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# ShellDemo Sample - -A comprehensive control showcase application demonstrating all OpenMaui Linux controls with Shell navigation and flyout menu. - -## Features - -- **Shell Navigation** - Flyout menu with multiple pages -- **Route-Based Navigation** - Push navigation with registered routes -- **All Core Controls** - Button, Entry, Editor, CheckBox, Switch, Slider, Picker, etc. -- **CollectionView** - Lists with selection and data binding -- **Progress Indicators** - ProgressBar and ActivityIndicator with animations -- **Grid Layouts** - Complex multi-column/row layouts -- **Event Logging** - Real-time event feedback panel - -## Pages - -| Page | Controls Demonstrated | -|------|----------------------| -| **Home** | Welcome screen, navigation overview | -| **Buttons** | Button styles, colors, states, click/press/release events | -| **Text Input** | Entry, Editor, SearchBar, password fields, keyboard types | -| **Selection** | CheckBox, Switch, Slider with colors and states | -| **Pickers** | Picker, DatePicker, TimePicker with styling | -| **Lists** | CollectionView with selection, custom items | -| **Progress** | ProgressBar, ActivityIndicator, animated demos | -| **Grids** | Grid layouts with row/column definitions | -| **About** | App information | - -## Architecture - -``` -ShellDemo/ -├── App.cs # AppShell definition with flyout -├── Program.cs # Linux platform bootstrap -├── MauiProgram.cs # MAUI app builder -└── Pages/ - ├── HomePage.cs # Welcome page - ├── ButtonsPage.cs # Button demonstrations - ├── TextInputPage.cs # Entry, Editor, SearchBar - ├── SelectionPage.cs # CheckBox, Switch, Slider - ├── PickersPage.cs # Picker, DatePicker, TimePicker - ├── ListsPage.cs # CollectionView demos - ├── ProgressPage.cs # ProgressBar, ActivityIndicator - ├── GridsPage.cs # Grid layout demos - ├── DetailPage.cs # Push navigation target - └── AboutPage.cs # About information -``` - -## Shell Configuration - -```csharp -public class AppShell : Shell -{ - public AppShell() - { - FlyoutBehavior = FlyoutBehavior.Flyout; - Title = "OpenMaui Controls Demo"; - - // Register routes for push navigation - Routing.RegisterRoute("detail", typeof(DetailPage)); - - // Add flyout items - Items.Add(CreateFlyoutItem("Home", typeof(HomePage))); - Items.Add(CreateFlyoutItem("Buttons", typeof(ButtonsPage))); - // ...more items - } -} -``` - -## Control Demonstrations - -### Buttons Page -- Default, styled, and transparent buttons -- Color variations (Primary, Success, Warning, Danger) -- Enabled/disabled state toggling -- Wide, tall, and round button shapes -- Pressed, clicked, released event handling - -### Text Input Page -- Entry with placeholder and text change events -- Password entry with hidden text -- Email keyboard type -- SearchBar with search button -- Multi-line Editor -- Keyboard shortcuts guide - -### Selection Page -- CheckBox with colors and disabled state -- Switch with OnColor customization -- Slider with min/max range and track colors - -### Pickers Page -- Picker with items and selection events -- DatePicker with date range limits -- TimePicker with time selection -- Styled pickers with custom colors - -### Lists Page -- CollectionView with string items -- CollectionView with custom data types (ColorItem, ContactItem) -- Selection handling and event feedback - -### Progress Page -- ProgressBar at various percentages -- Colored progress bars -- ActivityIndicator running/stopped states -- Colored activity indicators -- Interactive slider-controlled progress -- Animated progress simulation - -## Building and Running - -```bash -# From the maui-linux-push directory -cd samples/ShellDemo -dotnet publish -c Release -r linux-arm64 - -# Run on Linux -./bin/Release/net9.0/linux-arm64/publish/ShellDemo -``` - -## Event Logging - -Each page features an event log panel that displays control interactions in real-time: - -``` -[14:32:15] 3. Button clicked: Primary -[14:32:12] 2. Slider value: 75 -[14:32:08] 1. CheckBox: Checked -``` - -## Controls Reference - -| Control | Properties Demonstrated | -|---------|------------------------| -| Button | Text, BackgroundColor, TextColor, CornerRadius, IsEnabled, WidthRequest, HeightRequest | -| Entry | Placeholder, Text, IsPassword, Keyboard, FontSize | -| Editor | Placeholder, Text, HeightRequest | -| SearchBar | Placeholder, Text, SearchButtonPressed | -| CheckBox | IsChecked, Color, IsEnabled | -| Switch | IsToggled, OnColor, IsEnabled | -| Slider | Minimum, Maximum, Value, MinimumTrackColor, MaximumTrackColor, ThumbColor | -| Picker | Title, Items, SelectedIndex, TextColor, TitleColor | -| DatePicker | Date, MinimumDate, MaximumDate, TextColor | -| TimePicker | Time, TextColor | -| CollectionView | ItemsSource, SelectionMode, SelectionChanged, HeightRequest | -| ProgressBar | Progress, ProgressColor | -| ActivityIndicator | IsRunning, Color | -| Label | Text, FontSize, FontAttributes, TextColor | -| Frame | CornerRadius, Padding, BackgroundColor | -| Grid | RowDefinitions, ColumnDefinitions, RowSpacing, ColumnSpacing | -| StackLayout | Spacing, Padding, Orientation | -| ScrollView | Content scrolling | - -## License - -MIT License - See repository root for details. diff --git a/samples/ShellDemo/ShellDemo.csproj b/samples/ShellDemo/ShellDemo.csproj deleted file mode 100644 index 1c0d871..0000000 --- a/samples/ShellDemo/ShellDemo.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net9.0 - enable - enable - true - - - - - - - diff --git a/samples/TodoApp/App.cs b/samples/TodoApp/App.cs deleted file mode 100644 index 7ffbb8d..0000000 --- a/samples/TodoApp/App.cs +++ /dev/null @@ -1,21 +0,0 @@ -// TodoApp - Main Application with NavigationPage - -using Microsoft.Maui.Controls; - -namespace TodoApp; - -public class App : Application -{ - public static NavigationPage? NavigationPage { get; private set; } - - public App() - { - NavigationPage = new NavigationPage(new TodoListPage()) - { - Title = "OpenMaui Todo App", - BarBackgroundColor = Color.FromArgb("#2196F3"), - BarTextColor = Colors.White - }; - MainPage = NavigationPage; - } -} diff --git a/samples/TodoApp/MauiProgram.cs b/samples/TodoApp/MauiProgram.cs deleted file mode 100644 index 94b7677..0000000 --- a/samples/TodoApp/MauiProgram.cs +++ /dev/null @@ -1,22 +0,0 @@ -// MauiProgram.cs - MAUI app configuration - -using Microsoft.Maui.Hosting; -using Microsoft.Maui.Platform.Linux.Hosting; - -namespace TodoApp; - -public static class MauiProgram -{ - public static MauiApp CreateMauiApp() - { - var builder = MauiApp.CreateBuilder(); - - // Configure the app - builder.UseMauiApp(); - - // Add Linux platform support with all handlers - builder.UseLinux(); - - return builder.Build(); - } -} diff --git a/samples/TodoApp/NewTodoPage.xaml b/samples/TodoApp/NewTodoPage.xaml deleted file mode 100644 index 7f4f1a4..0000000 --- a/samples/TodoApp/NewTodoPage.xaml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - #5C6BC0 - #26A69A - #212121 - #757575 - #FFFFFF - #E8EAF6 - - - - - - - - - - - - - - - - - - - diff --git a/samples/TodoApp/NewTodoPage.xaml.cs b/samples/TodoApp/NewTodoPage.xaml.cs deleted file mode 100644 index ed1c90b..0000000 --- a/samples/TodoApp/NewTodoPage.xaml.cs +++ /dev/null @@ -1,31 +0,0 @@ -// NewTodoPage - Create a new todo item - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; - -namespace TodoApp; - -public partial class NewTodoPage : ContentPage -{ - private readonly TodoService _service = TodoService.Instance; - - public NewTodoPage() - { - InitializeComponent(); - } - - private async void OnSaveClicked(object? sender, EventArgs e) - { - var title = TitleEntry.Text?.Trim(); - - if (string.IsNullOrEmpty(title)) - { - TitleEntry.Placeholder = "Title is required!"; - TitleEntry.PlaceholderColor = Colors.Red; - return; - } - - _service.AddTodo(title, NotesEditor.Text ?? ""); - await Navigation.PopAsync(); - } -} diff --git a/samples/TodoApp/Program.cs b/samples/TodoApp/Program.cs deleted file mode 100644 index 1602090..0000000 --- a/samples/TodoApp/Program.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Program.cs - Linux platform entry point - -using Microsoft.Maui.Platform.Linux; - -namespace TodoApp; - -class Program -{ - static void Main(string[] args) - { - // Redirect console output to a log file for debugging - var logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "todoapp.log"); - using var logWriter = new StreamWriter(logPath, append: false) { AutoFlush = true }; - var multiWriter = new MultiTextWriter(Console.Out, logWriter); - Console.SetOut(multiWriter); - Console.SetError(multiWriter); - - // Global exception handler - AppDomain.CurrentDomain.UnhandledException += (sender, e) => - { - var ex = e.ExceptionObject as Exception; - Console.WriteLine($"[FATAL] Unhandled exception: {ex?.GetType().Name}: {ex?.Message}"); - Console.WriteLine($"[FATAL] Stack trace: {ex?.StackTrace}"); - if (ex?.InnerException != null) - { - Console.WriteLine($"[FATAL] Inner exception: {ex.InnerException.GetType().Name}: {ex.InnerException.Message}"); - Console.WriteLine($"[FATAL] Inner stack trace: {ex.InnerException.StackTrace}"); - } - }; - - TaskScheduler.UnobservedTaskException += (sender, e) => - { - Console.WriteLine($"[FATAL] Unobserved task exception: {e.Exception?.GetType().Name}: {e.Exception?.Message}"); - Console.WriteLine($"[FATAL] Stack trace: {e.Exception?.StackTrace}"); - e.SetObserved(); // Prevent crash - }; - - Console.WriteLine($"[Program] Starting TodoApp at {DateTime.Now}"); - Console.WriteLine($"[Program] Log file: {logPath}"); - - try - { - // Create the MAUI app with all handlers registered - var app = MauiProgram.CreateMauiApp(); - - // Run on Linux platform - LinuxApplication.Run(app, args); - } - catch (Exception ex) - { - Console.WriteLine($"[FATAL] Exception in Main: {ex.GetType().Name}: {ex.Message}"); - Console.WriteLine($"[FATAL] Stack trace: {ex.StackTrace}"); - throw; - } - } -} - -// Helper to write to both console and file -class MultiTextWriter : TextWriter -{ - private readonly TextWriter[] _writers; - public MultiTextWriter(params TextWriter[] writers) => _writers = writers; - public override System.Text.Encoding Encoding => System.Text.Encoding.UTF8; - public override void Write(char value) { foreach (var w in _writers) w.Write(value); } - public override void WriteLine(string? value) { foreach (var w in _writers) w.WriteLine(value); } - public override void Flush() { foreach (var w in _writers) w.Flush(); } -} diff --git a/samples/TodoApp/README.md b/samples/TodoApp/README.md deleted file mode 100644 index 67c5f85..0000000 --- a/samples/TodoApp/README.md +++ /dev/null @@ -1,111 +0,0 @@ -# TodoApp Sample - -A complete task management application demonstrating OpenMaui Linux capabilities with real-world XAML patterns. - -## Features - -- **NavigationPage** - Full page navigation with back button support -- **CollectionView** - Scrollable list with data binding and selection -- **XAML Data Binding** - Value converters for dynamic styling -- **DisplayAlert Dialogs** - Confirmation dialogs for delete actions -- **Grid Layouts** - Complex layouts with star sizing for expanding content -- **Entry & Editor** - Single and multi-line text input -- **Border with RoundRectangle** - Modern card-style UI -- **ToolbarItems** - Navigation bar actions - -## Screenshots - -The app consists of three pages: - -1. **TodoListPage** - Shows all tasks with completion status indicators -2. **NewTodoPage** - Create a new task with title and notes -3. **TodoDetailPage** - View/edit task details, mark complete, or delete - -## Architecture - -``` -TodoApp/ -├── App.cs # Application entry with NavigationPage -├── Program.cs # Linux platform bootstrap -├── MauiProgram.cs # MAUI app builder -├── TodoItem.cs # Data model -├── TodoService.cs # In-memory data store -├── TodoListPage.xaml(.cs) # Main list view -├── NewTodoPage.xaml(.cs) # Create task page -└── TodoDetailPage.xaml(.cs) # Task detail/edit page -``` - -## XAML Highlights - -### Value Converters -The app uses custom converters for dynamic styling based on completion status: -- `CompletedToColorConverter` - Gray text for completed items -- `CompletedToTextDecorationsConverter` - Strikethrough for completed items -- `CompletedToOpacityConverter` - Fade completed items -- `AlternatingRowColorConverter` - Alternating background colors - -### ResourceDictionary -```xml - - #5C6BC0 - #26A69A - #212121 - -``` - -### CollectionView with DataTemplate -```xml - - - - - - - - -``` - -### Grid with Star Rows (Expanding Editor) -```xml - - - - - - - -``` - -## Building and Running - -```bash -# From the maui-linux-push directory -cd samples/TodoApp -dotnet publish -c Release -r linux-arm64 - -# Run on Linux -./bin/Release/net9.0/linux-arm64/publish/TodoApp -``` - -## Controls Demonstrated - -| Control | Usage | -|---------|-------| -| NavigationPage | App navigation container | -| ContentPage | Individual screens | -| CollectionView | Task list with selection | -| Grid | Page layouts | -| VerticalStackLayout | Vertical grouping | -| HorizontalStackLayout | Horizontal grouping | -| Label | Text display | -| Entry | Single-line input | -| Editor | Multi-line input | -| Button | Toolbar actions | -| Border | Card styling with rounded corners | -| CheckBox | Completion toggle | -| BoxView | Visual separators | - -## License - -MIT License - See repository root for details. diff --git a/samples/TodoApp/TodoApp.csproj b/samples/TodoApp/TodoApp.csproj deleted file mode 100644 index 1c0d871..0000000 --- a/samples/TodoApp/TodoApp.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - Exe - net9.0 - enable - enable - true - - - - - - - diff --git a/samples/TodoApp/TodoDetailPage.xaml b/samples/TodoApp/TodoDetailPage.xaml deleted file mode 100644 index ea8037a..0000000 --- a/samples/TodoApp/TodoDetailPage.xaml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - #5C6BC0 - #26A69A - #EF5350 - #212121 - #757575 - #FFFFFF - #E8EAF6 - - - - - - - - - - - - - - - - diff --git a/samples/TodoApp/TodoDetailPage.xaml.cs b/samples/TodoApp/TodoDetailPage.xaml.cs deleted file mode 100644 index d0d1df5..0000000 --- a/samples/TodoApp/TodoDetailPage.xaml.cs +++ /dev/null @@ -1,91 +0,0 @@ -// TodoDetailPage - View and edit a todo item - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; -using Microsoft.Maui.Platform; - -namespace TodoApp; - -public partial class TodoDetailPage : ContentPage -{ - private readonly TodoItem _todo; - private readonly TodoService _service = TodoService.Instance; - - // Colors for status label - private static readonly Color AccentColor = Color.FromArgb("#26A69A"); - private static readonly Color TextPrimary = Color.FromArgb("#212121"); - - public TodoDetailPage(TodoItem todo) - { - try - { - Console.WriteLine($"[TodoDetailPage] Constructor starting for: {todo.Title}"); - InitializeComponent(); - Console.WriteLine($"[TodoDetailPage] InitializeComponent complete"); - - _todo = todo; - - // Populate fields - Console.WriteLine($"[TodoDetailPage] Setting TitleEntry.Text"); - TitleEntry.Text = _todo.Title; - Console.WriteLine($"[TodoDetailPage] Setting NotesEditor.Text"); - NotesEditor.Text = _todo.Notes; - Console.WriteLine($"[TodoDetailPage] Setting CompletedCheckBox.IsChecked"); - CompletedCheckBox.IsChecked = _todo.IsCompleted; - Console.WriteLine($"[TodoDetailPage] Calling UpdateStatusLabel"); - UpdateStatusLabel(_todo.IsCompleted); - Console.WriteLine($"[TodoDetailPage] Setting CreatedLabel.Text"); - CreatedLabel.Text = $"Created {_todo.CreatedAt:MMMM d, yyyy} at {_todo.CreatedAt:h:mm tt}"; - Console.WriteLine($"[TodoDetailPage] Constructor complete"); - } - catch (Exception ex) - { - Console.WriteLine($"[TodoDetailPage] EXCEPTION in constructor: {ex.GetType().Name}: {ex.Message}"); - Console.WriteLine($"[TodoDetailPage] Stack trace: {ex.StackTrace}"); - throw; - } - } - - private void OnCompletedChanged(object? sender, Microsoft.Maui.Controls.CheckedChangedEventArgs e) - { - Console.WriteLine($"[TodoDetailPage] OnCompletedChanged: {e.Value}"); - UpdateStatusLabel(e.Value); - } - - private void UpdateStatusLabel(bool isCompleted) - { - if (StatusLabel == null) - { - Console.WriteLine($"[TodoDetailPage] UpdateStatusLabel: StatusLabel is null, skipping"); - return; - } - Console.WriteLine($"[TodoDetailPage] UpdateStatusLabel: setting to {(isCompleted ? "Completed" : "In Progress")}"); - StatusLabel.Text = isCompleted ? "Completed" : "In Progress"; - StatusLabel.TextColor = isCompleted ? AccentColor : TextPrimary; - } - - private async void OnSaveClicked(object? sender, EventArgs e) - { - _todo.Title = TitleEntry.Text ?? ""; - _todo.Notes = NotesEditor.Text ?? ""; - _todo.IsCompleted = CompletedCheckBox.IsChecked; - - await Navigation.PopAsync(); - } - - private async void OnDeleteClicked(object? sender, EventArgs e) - { - // Show confirmation dialog - var confirmed = await LinuxDialogService.ShowAlertAsync( - "Delete Task", - $"Are you sure you want to delete \"{_todo.Title}\"? This action cannot be undone.", - "Delete", - "Cancel"); - - if (confirmed) - { - _service.DeleteTodo(_todo); - await Navigation.PopAsync(); - } - } -} diff --git a/samples/TodoApp/TodoItem.cs b/samples/TodoApp/TodoItem.cs deleted file mode 100644 index e7ab47c..0000000 --- a/samples/TodoApp/TodoItem.cs +++ /dev/null @@ -1,81 +0,0 @@ -// TodoItem - Data model for a todo item - -using System.ComponentModel; - -namespace TodoApp; - -public class TodoItem : INotifyPropertyChanged -{ - private string _title = ""; - private string _notes = ""; - private bool _isCompleted; - private DateTime _dueDate; - - public int Id { get; set; } - - /// - /// Index in the collection for alternating row colors. - /// - public int Index { get; set; } - - public string Title - { - get => _title; - set - { - if (_title != value) - { - _title = value; - OnPropertyChanged(nameof(Title)); - } - } - } - - public string Notes - { - get => _notes; - set - { - if (_notes != value) - { - _notes = value; - OnPropertyChanged(nameof(Notes)); - } - } - } - - public bool IsCompleted - { - get => _isCompleted; - set - { - if (_isCompleted != value) - { - _isCompleted = value; - OnPropertyChanged(nameof(IsCompleted)); - } - } - } - - public DateTime DueDate - { - get => _dueDate; - set - { - if (_dueDate != value) - { - _dueDate = value; - OnPropertyChanged(nameof(DueDate)); - } - } - } - - public DateTime CreatedAt { get; set; } = DateTime.Now; - - public event PropertyChangedEventHandler? PropertyChanged; - - protected void OnPropertyChanged(string propertyName) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } -} diff --git a/samples/TodoApp/TodoListPage.xaml b/samples/TodoApp/TodoListPage.xaml deleted file mode 100644 index 9299260..0000000 --- a/samples/TodoApp/TodoListPage.xaml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - #5C6BC0 - #3949AB - #26A69A - #212121 - #757575 - #FFFFFF - #E0E0E0 - #9E9E9E - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/samples/TodoApp/TodoListPage.xaml.cs b/samples/TodoApp/TodoListPage.xaml.cs deleted file mode 100644 index 204541b..0000000 --- a/samples/TodoApp/TodoListPage.xaml.cs +++ /dev/null @@ -1,174 +0,0 @@ -// TodoListPage - Main page for viewing todos with XAML support - -using Microsoft.Maui.Controls; -using Microsoft.Maui.Graphics; -using System.Globalization; - -namespace TodoApp; - -public partial class TodoListPage : ContentPage -{ - private readonly TodoService _service = TodoService.Instance; - - public TodoListPage() - { - Console.WriteLine("[TodoListPage] Constructor starting"); - InitializeComponent(); - - TodoCollectionView.ItemsSource = _service.Todos; - UpdateStats(); - - Console.WriteLine("[TodoListPage] Constructor finished"); - } - - protected override void OnAppearing() - { - Console.WriteLine("[TodoListPage] OnAppearing called - refreshing CollectionView"); - base.OnAppearing(); - - // Refresh indexes for alternating row colors - _service.RefreshIndexes(); - - // Refresh the collection view - TodoCollectionView.ItemsSource = null; - TodoCollectionView.ItemsSource = _service.Todos; - Console.WriteLine($"[TodoListPage] ItemsSource set with {_service.Todos.Count} items"); - UpdateStats(); - } - - private async void OnAddClicked(object sender, EventArgs e) - { - await Navigation.PushAsync(new NewTodoPage()); - } - - private async void OnSelectionChanged(object? sender, SelectionChangedEventArgs e) - { - try - { - Console.WriteLine($"[TodoListPage] OnSelectionChanged: {e.CurrentSelection.Count} items selected"); - if (e.CurrentSelection.FirstOrDefault() is TodoItem todo) - { - Console.WriteLine($"[TodoListPage] Navigating to TodoDetailPage for: {todo.Title}"); - TodoCollectionView.SelectedItem = null; // Deselect - var detailPage = new TodoDetailPage(todo); - Console.WriteLine($"[TodoListPage] Created TodoDetailPage, pushing..."); - await Navigation.PushAsync(detailPage); - Console.WriteLine($"[TodoListPage] Navigation complete"); - } - } - catch (Exception ex) - { - Console.WriteLine($"[TodoListPage] EXCEPTION in OnSelectionChanged: {ex.GetType().Name}: {ex.Message}"); - Console.WriteLine($"[TodoListPage] Stack trace: {ex.StackTrace}"); - } - } - - private void UpdateStats() - { - var completed = _service.CompletedCount; - var total = _service.TotalCount; - - if (total == 0) - { - StatsLabel.Text = ""; - } - else - { - StatsLabel.Text = $"{completed} of {total} completed"; - } - } -} - -/// -/// Converter for alternating row background colors. -/// -public class AlternatingRowColorConverter : IValueConverter -{ - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - if (value is int index) - { - return index % 2 == 0 ? Colors.White : Color.FromArgb("#F5F5F5"); - } - return Colors.White; - } - - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} - -/// -/// Converter for completed task text color and indicator color. -/// -public class CompletedToColorConverter : IValueConverter -{ - // Define colors - private static readonly Color PrimaryColor = Color.FromArgb("#5C6BC0"); - private static readonly Color AccentColor = Color.FromArgb("#26A69A"); - private static readonly Color CompletedColor = Color.FromArgb("#9E9E9E"); - private static readonly Color TextPrimary = Color.FromArgb("#212121"); - private static readonly Color TextSecondary = Color.FromArgb("#757575"); - - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - bool isCompleted = value is bool b && b; - string param = parameter as string ?? ""; - - // Indicator bar color - if (param == "indicator") - { - return isCompleted ? CompletedColor : AccentColor; - } - - // Text colors - if (isCompleted) - { - return CompletedColor; - } - else - { - return param == "notes" ? TextSecondary : TextPrimary; - } - } - - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} - -/// -/// Converter for completed task text decorations (strikethrough). -/// -public class CompletedToTextDecorationsConverter : IValueConverter -{ - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - bool isCompleted = value is bool b && b; - return isCompleted ? TextDecorations.Strikethrough : TextDecorations.None; - } - - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} - -/// -/// Converter for completed task opacity (slightly faded when complete). -/// -public class CompletedToOpacityConverter : IValueConverter -{ - public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) - { - bool isCompleted = value is bool b && b; - return isCompleted ? 0.7 : 1.0; - } - - public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} diff --git a/samples/TodoApp/TodoService.cs b/samples/TodoApp/TodoService.cs deleted file mode 100644 index f03844b..0000000 --- a/samples/TodoApp/TodoService.cs +++ /dev/null @@ -1,61 +0,0 @@ -// TodoService - Manages todo items - -using System.Collections.ObjectModel; - -namespace TodoApp; - -public class TodoService -{ - private static TodoService? _instance; - public static TodoService Instance => _instance ??= new TodoService(); - - private int _nextId = 1; - - public ObservableCollection Todos { get; } = new(); - - private TodoService() - { - // Add sample todos with varying lengths to test MaxLines=2 with ellipsis - AddTodo("Learn OpenMaui Linux", "Explore the SkiaSharp-based rendering engine for .NET MAUI on Linux desktop. This is a very long description that should wrap to multiple lines and demonstrate the ellipsis truncation feature when MaxLines is set to 2."); - AddTodo("Build amazing apps", "Create cross-platform applications that run on Windows, macOS, iOS, Android, and Linux! With OpenMaui, you can write once and deploy everywhere."); - AddTodo("Share with the community", "Contribute to the open-source project and help others build great Linux apps. Join our growing community of developers who are passionate about bringing .NET MAUI to Linux."); - } - - public TodoItem AddTodo(string title, string notes = "") - { - var todo = new TodoItem - { - Id = _nextId++, - Index = Todos.Count, // Set index for alternating row colors - Title = title, - Notes = notes, - DueDate = DateTime.Today.AddDays(7) - }; - Todos.Add(todo); - return todo; - } - - /// - /// Refreshes the Index property on all items for alternating row colors. - /// - public void RefreshIndexes() - { - for (int i = 0; i < Todos.Count; i++) - { - Todos[i].Index = i; - } - } - - public TodoItem? GetTodo(int id) - { - return Todos.FirstOrDefault(t => t.Id == id); - } - - public void DeleteTodo(TodoItem todo) - { - Todos.Remove(todo); - } - - public int CompletedCount => Todos.Count(t => t.IsCompleted); - public int TotalCount => Todos.Count; -}