NavigationPageMvvmPageFactory.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. using System;
  2. using Avalonia;
  3. using Avalonia.Controls;
  4. using Avalonia.Controls.Templates;
  5. using Avalonia.Layout;
  6. using Avalonia.Media;
  7. using MiniMvvm;
  8. namespace ControlCatalog.Pages
  9. {
  10. internal sealed class SamplePageFactory : ISamplePageFactory
  11. {
  12. public ContentPage CreatePage(ViewModelBase viewModel) =>
  13. viewModel switch
  14. {
  15. WorkspaceViewModel workspace => CreateWorkspacePage(workspace),
  16. ProjectDetailViewModel detail => CreateProjectDetailPage(detail),
  17. ProjectActivityViewModel activity => CreateProjectActivityPage(activity),
  18. _ => throw new InvalidOperationException($"Unsupported view model: {viewModel.GetType().Name}")
  19. };
  20. private static ContentPage CreateWorkspacePage(WorkspaceViewModel viewModel)
  21. {
  22. var stack = new StackPanel
  23. {
  24. Margin = new Thickness(20),
  25. Spacing = 14,
  26. };
  27. stack.Children.Add(new TextBlock
  28. {
  29. Text = viewModel.Title,
  30. FontSize = 24,
  31. FontWeight = FontWeight.Bold,
  32. });
  33. stack.Children.Add(new TextBlock
  34. {
  35. Text = viewModel.Description,
  36. FontSize = 13,
  37. Opacity = 0.75,
  38. TextWrapping = TextWrapping.Wrap,
  39. });
  40. stack.Children.Add(new ItemsControl
  41. {
  42. ItemsSource = viewModel.Projects,
  43. ItemTemplate = new FuncDataTemplate<ProjectCardViewModel>((item, _) =>
  44. {
  45. if (item == null)
  46. return new TextBlock();
  47. var accentBrush = new SolidColorBrush(item.AccentColor);
  48. var statusBadge = new Border
  49. {
  50. Background = accentBrush,
  51. CornerRadius = new CornerRadius(999),
  52. Padding = new Thickness(10, 4),
  53. Child = new TextBlock
  54. {
  55. Text = item.Status,
  56. Foreground = Brushes.White,
  57. FontSize = 11,
  58. FontWeight = FontWeight.SemiBold,
  59. }
  60. };
  61. DockPanel.SetDock(statusBadge, Dock.Right);
  62. var header = new DockPanel();
  63. header.Children.Add(statusBadge);
  64. header.Children.Add(new TextBlock
  65. {
  66. Text = item.Name,
  67. FontSize = 17,
  68. FontWeight = FontWeight.SemiBold,
  69. });
  70. return new Border
  71. {
  72. Background = new SolidColorBrush(Color.FromArgb(20, item.AccentColor.R, item.AccentColor.G, item.AccentColor.B)),
  73. BorderBrush = accentBrush,
  74. BorderThickness = new Thickness(1),
  75. CornerRadius = new CornerRadius(8),
  76. Padding = new Thickness(14),
  77. Margin = new Thickness(0, 0, 0, 8),
  78. Child = new StackPanel
  79. {
  80. Spacing = 8,
  81. Children =
  82. {
  83. header,
  84. new TextBlock
  85. {
  86. Text = item.Summary,
  87. FontSize = 13,
  88. Opacity = 0.72,
  89. TextWrapping = TextWrapping.Wrap,
  90. },
  91. new TextBlock
  92. {
  93. Text = $"Owner: {item.Owner} • Next: {item.NextMilestone}",
  94. FontSize = 12,
  95. Opacity = 0.6,
  96. TextWrapping = TextWrapping.Wrap,
  97. },
  98. new Button
  99. {
  100. Content = "Open Project",
  101. HorizontalAlignment = HorizontalAlignment.Left,
  102. Command = item.OpenCommand,
  103. }
  104. }
  105. }
  106. };
  107. })
  108. });
  109. var page = new ContentPage
  110. {
  111. Header = "Workspace",
  112. Content = new ScrollViewer { Content = stack },
  113. HorizontalContentAlignment = HorizontalAlignment.Stretch,
  114. VerticalContentAlignment = VerticalAlignment.Stretch,
  115. };
  116. NavigationPage.SetHasBackButton(page, false);
  117. return page;
  118. }
  119. private static ContentPage CreateProjectDetailPage(ProjectDetailViewModel viewModel)
  120. {
  121. var accentBrush = new SolidColorBrush(viewModel.AccentColor);
  122. var panel = new StackPanel
  123. {
  124. Margin = new Thickness(24, 20),
  125. Spacing = 12,
  126. };
  127. panel.Children.Add(new Border
  128. {
  129. Background = accentBrush,
  130. CornerRadius = new CornerRadius(999),
  131. Padding = new Thickness(12, 5),
  132. HorizontalAlignment = HorizontalAlignment.Left,
  133. Child = new TextBlock
  134. {
  135. Text = viewModel.Status,
  136. Foreground = Brushes.White,
  137. FontSize = 11,
  138. FontWeight = FontWeight.SemiBold,
  139. }
  140. });
  141. panel.Children.Add(new TextBlock
  142. {
  143. Text = viewModel.Name,
  144. FontSize = 26,
  145. FontWeight = FontWeight.Bold,
  146. });
  147. panel.Children.Add(new TextBlock
  148. {
  149. Text = viewModel.Summary,
  150. FontSize = 14,
  151. Opacity = 0.78,
  152. TextWrapping = TextWrapping.Wrap,
  153. });
  154. panel.Children.Add(new TextBlock
  155. {
  156. Text = $"Owner: {viewModel.Owner}",
  157. FontSize = 13,
  158. Opacity = 0.68,
  159. });
  160. panel.Children.Add(new TextBlock
  161. {
  162. Text = $"Next milestone: {viewModel.NextMilestone}",
  163. FontSize = 13,
  164. Opacity = 0.68,
  165. TextWrapping = TextWrapping.Wrap,
  166. });
  167. panel.Children.Add(new Separator { Margin = new Thickness(0, 4) });
  168. panel.Children.Add(new TextBlock
  169. {
  170. Text = "This page is resolved by SamplePageFactory from a ProjectDetailViewModel. The view model only requests navigation through ISampleNavigationService.",
  171. FontSize = 12,
  172. Opacity = 0.7,
  173. TextWrapping = TextWrapping.Wrap,
  174. });
  175. panel.Children.Add(new Button
  176. {
  177. Content = "Open Activity",
  178. HorizontalAlignment = HorizontalAlignment.Left,
  179. Command = viewModel.OpenActivityCommand,
  180. });
  181. return new ContentPage
  182. {
  183. Header = viewModel.Name,
  184. Background = new SolidColorBrush(Color.FromArgb(18, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
  185. Content = new ScrollViewer { Content = panel },
  186. HorizontalContentAlignment = HorizontalAlignment.Stretch,
  187. VerticalContentAlignment = VerticalAlignment.Stretch,
  188. };
  189. }
  190. private static ContentPage CreateProjectActivityPage(ProjectActivityViewModel viewModel)
  191. {
  192. var panel = new StackPanel
  193. {
  194. Margin = new Thickness(24, 20),
  195. Spacing = 10,
  196. };
  197. panel.Children.Add(new TextBlock
  198. {
  199. Text = "Activity Timeline",
  200. FontSize = 24,
  201. FontWeight = FontWeight.Bold,
  202. });
  203. panel.Children.Add(new TextBlock
  204. {
  205. Text = $"Recent updates for {viewModel.Name}. This page was opened from a command on the detail view model.",
  206. FontSize = 13,
  207. Opacity = 0.74,
  208. TextWrapping = TextWrapping.Wrap,
  209. });
  210. foreach (var item in viewModel.Items)
  211. {
  212. panel.Children.Add(new Border
  213. {
  214. Background = new SolidColorBrush(Color.FromArgb(14, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
  215. BorderBrush = new SolidColorBrush(Color.FromArgb(80, viewModel.AccentColor.R, viewModel.AccentColor.G, viewModel.AccentColor.B)),
  216. BorderThickness = new Thickness(1),
  217. CornerRadius = new CornerRadius(6),
  218. Padding = new Thickness(12, 10),
  219. Child = new TextBlock
  220. {
  221. Text = item,
  222. FontSize = 13,
  223. TextWrapping = TextWrapping.Wrap,
  224. }
  225. });
  226. }
  227. return new ContentPage
  228. {
  229. Header = "Activity",
  230. Content = new ScrollViewer { Content = panel },
  231. HorizontalContentAlignment = HorizontalAlignment.Stretch,
  232. VerticalContentAlignment = VerticalAlignment.Stretch,
  233. };
  234. }
  235. }
  236. }