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.
 
 
 

252 lines
9.6 KiB

using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Avalonia.Media;
using MiniMvvm;
namespace ControlCatalog.Pages
{
internal sealed class SamplePageFactory : ISamplePageFactory
{
public ContentPage CreatePage(ViewModelBase viewModel) =>
viewModel switch
{
WorkspaceViewModel workspace => CreateWorkspacePage(workspace),
ProjectDetailViewModel detail => CreateProjectDetailPage(detail),
ProjectActivityViewModel activity => CreateProjectActivityPage(activity),
_ => throw new InvalidOperationException($"Unsupported view model: {viewModel.GetType().Name}")
};
private static ContentPage CreateWorkspacePage(WorkspaceViewModel viewModel)
{
var stack = new StackPanel
{
Margin = new Thickness(20),
Spacing = 14,
};
stack.Children.Add(new TextBlock
{
Text = viewModel.Title,
FontSize = 24,
FontWeight = FontWeight.Bold,
});
stack.Children.Add(new TextBlock
{
Text = viewModel.Description,
FontSize = 13,
Opacity = 0.75,
TextWrapping = TextWrapping.Wrap,
});
stack.Children.Add(new ItemsControl
{
ItemsSource = viewModel.Projects,
ItemTemplate = new FuncDataTemplate<ProjectCardViewModel>((item, _) =>
{
if (item == null)
return new TextBlock();
var accentBrush = new SolidColorBrush(item.AccentColor);
var statusBadge = new Border
{
Background = accentBrush,
CornerRadius = new CornerRadius(999),
Padding = new Thickness(10, 4),
Child = new TextBlock
{
Text = item.Status,
Foreground = Brushes.White,
FontSize = 11,
FontWeight = FontWeight.SemiBold,
}
};
DockPanel.SetDock(statusBadge, Dock.Right);
var header = new DockPanel();
header.Children.Add(statusBadge);
header.Children.Add(new TextBlock
{
Text = item.Name,
FontSize = 17,
FontWeight = FontWeight.SemiBold,
});
return new Border
{
Background = new SolidColorBrush(Color.FromArgb(20, item.AccentColor.R, item.AccentColor.G, item.AccentColor.B)),
BorderBrush = accentBrush,
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(8),
Padding = new Thickness(14),
Margin = new Thickness(0, 0, 0, 8),
Child = new StackPanel
{
Spacing = 8,
Children =
{
header,
new TextBlock
{
Text = item.Summary,
FontSize = 13,
Opacity = 0.72,
TextWrapping = TextWrapping.Wrap,
},
new TextBlock
{
Text = $"Owner: {item.Owner} • Next: {item.NextMilestone}",
FontSize = 12,
Opacity = 0.6,
TextWrapping = TextWrapping.Wrap,
},
new Button
{
Content = "Open Project",
HorizontalAlignment = HorizontalAlignment.Left,
Command = item.OpenCommand,
}
}
}
};
})
});
var page = new ContentPage
{
Header = "Workspace",
Content = new ScrollViewer { Content = stack },
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
NavigationPage.SetHasBackButton(page, false);
return page;
}
private static ContentPage CreateProjectDetailPage(ProjectDetailViewModel viewModel)
{
var accentBrush = new SolidColorBrush(viewModel.AccentColor);
var panel = new StackPanel
{
Margin = new Thickness(24, 20),
Spacing = 12,
};
panel.Children.Add(new Border
{
Background = accentBrush,
CornerRadius = new CornerRadius(999),
Padding = new Thickness(12, 5),
HorizontalAlignment = HorizontalAlignment.Left,
Child = new TextBlock
{
Text = viewModel.Status,
Foreground = Brushes.White,
FontSize = 11,
FontWeight = FontWeight.SemiBold,
}
});
panel.Children.Add(new TextBlock
{
Text = viewModel.Name,
FontSize = 26,
FontWeight = FontWeight.Bold,
});
panel.Children.Add(new TextBlock
{
Text = viewModel.Summary,
FontSize = 14,
Opacity = 0.78,
TextWrapping = TextWrapping.Wrap,
});
panel.Children.Add(new TextBlock
{
Text = $"Owner: {viewModel.Owner}",
FontSize = 13,
Opacity = 0.68,
});
panel.Children.Add(new TextBlock
{
Text = $"Next milestone: {viewModel.NextMilestone}",
FontSize = 13,
Opacity = 0.68,
TextWrapping = TextWrapping.Wrap,
});
panel.Children.Add(new Separator { Margin = new Thickness(0, 4) });
panel.Children.Add(new TextBlock
{
Text = "This page is resolved by SamplePageFactory from a ProjectDetailViewModel. The view model only requests navigation through ISampleNavigationService.",
FontSize = 12,
Opacity = 0.7,
TextWrapping = TextWrapping.Wrap,
});
panel.Children.Add(new Button
{
Content = "Open Activity",
HorizontalAlignment = HorizontalAlignment.Left,
Command = viewModel.OpenActivityCommand,
});
return new ContentPage
{
Header = viewModel.Name,
Background = new SolidColorBrush(Color.FromArgb(18, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
Content = new ScrollViewer { Content = panel },
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
}
private static ContentPage CreateProjectActivityPage(ProjectActivityViewModel viewModel)
{
var panel = new StackPanel
{
Margin = new Thickness(24, 20),
Spacing = 10,
};
panel.Children.Add(new TextBlock
{
Text = "Activity Timeline",
FontSize = 24,
FontWeight = FontWeight.Bold,
});
panel.Children.Add(new TextBlock
{
Text = $"Recent updates for {viewModel.Name}. This page was opened from a command on the detail view model.",
FontSize = 13,
Opacity = 0.74,
TextWrapping = TextWrapping.Wrap,
});
foreach (var item in viewModel.Items)
{
panel.Children.Add(new Border
{
Background = new SolidColorBrush(Color.FromArgb(14, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
BorderBrush = new SolidColorBrush(Color.FromArgb(80, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
BorderThickness = new Thickness(1),
CornerRadius = new CornerRadius(6),
Padding = new Thickness(12, 10),
Child = new TextBlock
{
Text = item,
FontSize = 13,
TextWrapping = TextWrapping.Wrap,
}
});
}
return new ContentPage
{
Header = "Activity",
Content = new ScrollViewer { Content = panel },
HorizontalContentAlignment = HorizontalAlignment.Stretch,
VerticalContentAlignment = VerticalAlignment.Stretch,
};
}
}
}