A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

262 lines
9.9 KiB

using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Styling;
namespace ControlCatalog.Pages;
public partial class LAvenirAppPage : UserControl
{
static readonly Color Primary = Color.Parse("#4b2bee");
static readonly Color BgDark = Color.Parse("#131022");
static readonly Color BgLight = Color.Parse("#f6f6f8");
static readonly Color TextDark = Color.Parse("#1e293b");
static readonly Color TextMuted = Color.Parse("#94a3b8");
static readonly Color BorderLight = Color.Parse("#e2e8f0");
NavigationPage? _navPage;
DrawerPage? _drawerPage;
ScrollViewer? _infoPanel;
public LAvenirAppPage()
{
InitializeComponent();
_navPage = this.FindControl<NavigationPage>("NavPage");
_drawerPage = this.FindControl<DrawerPage>("DrawerPageControl");
if (_navPage != null)
_ = _navPage.PushAsync(BuildMenuTabbedPage());
}
protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);
_infoPanel = this.FindControl<ScrollViewer>("InfoPanel");
UpdateInfoPanelVisibility();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == BoundsProperty)
UpdateInfoPanelVisibility();
}
void UpdateInfoPanelVisibility()
{
if (_infoPanel != null)
_infoPanel.IsVisible = Bounds.Width >= 650;
}
void ApplyRootNavigationBarAppearance()
{
if (_navPage == null)
return;
_navPage.Background = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgLight);
_navPage.Resources["NavigationBarForeground"] = new SolidColorBrush(TextDark);
}
void ApplyDetailNavigationBarAppearance()
{
if (_navPage == null)
return;
_navPage.Background = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarBackground"] = new SolidColorBrush(BgDark);
_navPage.Resources["NavigationBarForeground"] = Brushes.White;
}
TabbedPage BuildMenuTabbedPage()
{
var tp = new TabbedPage
{
Background = new SolidColorBrush(BgLight),
TabPlacement = TabPlacement.Bottom,
PageTransition = new PageSlide(TimeSpan.FromMilliseconds(200)),
};
tp.Resources["TabItemHeaderFontSize"] = 12.0;
tp.Resources["TabbedPageTabStripBackground"] = Brushes.White;
tp.Resources["TabbedPageTabStripBorderThickness"] = new Thickness(0, 1, 0, 0);
tp.Resources["TabbedPageTabStripBorderBrush"] = new SolidColorBrush(BorderLight);
tp.Resources["TabbedPageTabItemHeaderForegroundSelected"] = new SolidColorBrush(Primary);
tp.Resources["TabbedPageTabItemHeaderForegroundUnselected"] = new SolidColorBrush(TextMuted);
tp.IndicatorTemplate = new FuncDataTemplate<object>((_, _) =>
new Ellipse
{
Width = 5, Height = 5,
Margin = new Thickness(0, 10, 0, 0),
HorizontalAlignment = HorizontalAlignment.Center,
Fill = new SolidColorBrush(Primary),
});
tp.Header = new TextBlock
{
Text = "L'Avenir",
FontSize = 18,
FontWeight = FontWeight.Bold,
Foreground = new SolidColorBrush(TextDark),
VerticalAlignment = VerticalAlignment.Center,
TextAlignment = TextAlignment.Center,
};
ApplyRootNavigationBarAppearance();
NavigationPage.SetTopCommandBar(tp, new Button
{
Width = 40,
Height = 40,
CornerRadius = new CornerRadius(12),
Background = Brushes.Transparent,
Foreground = new SolidColorBrush(TextDark),
Padding = new Thickness(8),
BorderThickness = new Thickness(0),
Content = new PathIcon
{
Data = Geometry.Parse("M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"),
Width = 18,
Height = 18,
},
VerticalAlignment = VerticalAlignment.Center,
});
var menuView = new LAvenirMenuView();
menuView.DishSelected = PushDishDetail;
var menuPage = new ContentPage
{
Content = menuView,
Background = new SolidColorBrush(BgLight),
Header = "Menu",
Icon = Geometry.Parse("M11 9H9V2H7v7H5V2H3v7c0 2.12 1.66 3.84 3.75 3.97V22h2.5v-9.03C11.34 12.84 13 11.12 13 9V2h-2v7zm5-3v8h2.5v8H21V2c-2.76 0-5 2.24-5 4z"),
};
var reservationsPage = new ContentPage
{
Content = new LAvenirReservationsView(),
Background = new SolidColorBrush(BgLight),
Header = "Reservations",
Icon = Geometry.Parse("M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM9 10H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z"),
};
var profilePage = new ContentPage
{
Content = new LAvenirProfileView(),
Background = new SolidColorBrush(BgLight),
Header = "Profile",
Icon = Geometry.Parse("M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"),
};
tp.Pages = new ObservableCollection<Page> { menuPage, reservationsPage, profilePage };
return tp;
}
async void PushDishDetail(string name, string price, string description, string imageFile)
{
if (_navPage == null)
return;
var detail = new ContentPage
{
Content = new LAvenirDishDetailView(name, price, description, imageFile),
Background = new SolidColorBrush(BgDark),
Header = name,
};
NavigationPage.SetBottomCommandBar(detail, BuildFloatingBar(price));
detail.Navigating += args =>
{
if (args.NavigationType == NavigationType.Pop)
ApplyRootNavigationBarAppearance();
return Task.CompletedTask;
};
ApplyDetailNavigationBarAppearance();
await _navPage.PushAsync(detail);
if (!ReferenceEquals(_navPage.CurrentPage, detail))
ApplyRootNavigationBarAppearance();
}
Border BuildFloatingBar(string price)
{
var bar = new Border
{
CornerRadius = new CornerRadius(16),
Background = new SolidColorBrush(Color.FromArgb(178, BgDark.R, BgDark.G, BgDark.B)),
BorderBrush = new SolidColorBrush(Color.FromArgb(51, 255, 255, 255)),
BorderThickness = new Thickness(1),
Padding = new Thickness(16, 12),
Margin = new Thickness(16, 8, 16, 8),
};
var barGrid = new Grid { ColumnDefinitions = new ColumnDefinitions("*,Auto") };
var info = new StackPanel { VerticalAlignment = VerticalAlignment.Center };
info.Children.Add(new TextBlock
{
Text = "Add to Order",
FontSize = 14,
FontWeight = FontWeight.Bold,
Foreground = Brushes.White,
});
info.Children.Add(new TextBlock
{
Text = price,
FontSize = 12,
FontWeight = FontWeight.Medium,
Foreground = new SolidColorBrush(TextMuted),
});
barGrid.Children.Add(info);
var addBtn = new Button
{
Content = "Add",
Width = 80,
Height = 40,
CornerRadius = new CornerRadius(10),
Background = new SolidColorBrush(Primary),
Foreground = Brushes.White,
FontWeight = FontWeight.Bold,
FontSize = 14,
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center,
};
var hoverStyle = new Style(x => x.OfType<Button>().Class(":pointerover").Descendant().OfType<ContentPresenter>());
hoverStyle.Setters.Add(new Setter(ContentPresenter.BackgroundProperty, new SolidColorBrush(Color.Parse("#3d22cc"))));
hoverStyle.Setters.Add(new Setter(ContentPresenter.ForegroundProperty, Brushes.White));
addBtn.Styles.Add(hoverStyle);
var pressStyle = new Style(x => x.OfType<Button>().Class(":pressed").Descendant().OfType<ContentPresenter>());
pressStyle.Setters.Add(new Setter(ContentPresenter.BackgroundProperty, new SolidColorBrush(Color.Parse("#3518b0"))));
pressStyle.Setters.Add(new Setter(ContentPresenter.ForegroundProperty, Brushes.White));
addBtn.Styles.Add(pressStyle);
Grid.SetColumn(addBtn, 1);
barGrid.Children.Add(addBtn);
bar.Child = barGrid;
return bar;
}
void OnMenuItemClick(object? sender, RoutedEventArgs e)
{
if (sender is not Button btn || btn.Tag is not string) return;
if (_drawerPage != null)
_drawerPage.IsOpen = false;
_ = _navPage?.PopToRootAsync();
}
}