Skip to content

Commit b68128f

Browse files
Zakariathr22niels9001Copilot
authored
Add personalization features: Favorites and Recently Viewed Samples (#1875)
## Description This PR introduces **Favorites** and **Recently Viewed Samples** to enhance personalization. These features aim to improve navigation efficiency and user engagement. **Main changes are:** - Added StringListSettingsHelper class to manage storing/retrieving recently viewed and favorite samples. - Integrated favorite button in page headers with full persistence logic. - Introduced HorizontalScrollContainer control (adapted from AI Dev Gallery's TileGallery). - Refactored HomePage layout to include recent/favorite tabs using the new components. - Created and applied new styles: SingleRowGridViewItemStyle, TokenViewSelectorBarStyle, and TokenViewSelectorBarItemStyle. (SelectorBar styles was adapted from AI Dev Gallery) - Moved sample click logic into the ItemTemplate for better reuse and separation of concerns. - Removed obsolete click-handling logic from all pages now using the updated template. - Redesigned ItemTemplate layout to align visually with the HorizontalScrollContainer. - Added new settings card to SettingsPage with options to clear recently visited samples and unfavorite all items. - Design tweaks. ## Motivation and Context - This update brings user-centric personalization, allowing quick access to preferred and recent samples. - Closes #1862 ## How Has This Been Tested? Manually tested. ## Screenshots (if appropriate) ![image](https://github.com/user-attachments/assets/b6750d62-ca70-450a-8b33-e14abefa7450) ![image](https://github.com/user-attachments/assets/d88d8cde-e770-4fcb-af57-bf6f675cca2b) ![image](https://github.com/user-attachments/assets/77da5674-b832-4733-88e5-4eded0c9b847) ![image](https://github.com/user-attachments/assets/50c69e3f-4b6e-474b-a368-b6fc3d4a6906) ![image](https://github.com/user-attachments/assets/03ddab8f-16dc-4d36-897e-063c305d40ef) ## Types of changes <!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [x] Breaking change (fix or feature that would cause existing functionality to change) ## References - [ApplicationData - Windows App SDK](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.windows.storage.applicationdata?view=windows-app-sdk-1.7) - https://datatracker.ietf.org/doc/html/rfc8259#section-7 - [Unicode U+001F](https://www.compart.com/en/unicode/U+001F) --------- Co-authored-by: Niels Laute <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 1f88f93 commit b68128f

27 files changed

+1280
-573
lines changed

WinUIGallery/App.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
2222
<local:ItemTemplates />
2323
<ResourceDictionary Source="ms-appx:///Controls/CopyButton.xaml" />
24+
<ResourceDictionary Source="ms-appx:///Controls/OpacityMaskView.xaml" />
2425
<ResourceDictionary Source="ms-appx:///Styles/Button.xaml" />
2526
<ResourceDictionary Source="ms-appx:///Styles/Grid.xaml" />
2627
<ResourceDictionary Source="ms-appx:///Styles/GridViewItem.xaml" />
2728
<ResourceDictionary Source="ms-appx:///Styles/TextBlock.xaml" />
29+
<ResourceDictionary Source="ms-appx:///Styles/SelectorBar.xaml" />
2830
<ResourceDictionary Source="ms-appx:///Samples/ControlPages/Fundamentals/Controls/CounterControl.xaml" />
2931
<ResourceDictionary Source="ms-appx:///Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.xaml" />
3032
</ResourceDictionary.MergedDictionaries>

WinUIGallery/App.xaml.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs ar
6565
startupWindow.ExtendsContentIntoTitleBar = true;
6666

6767
win32WindowHelper = new Win32WindowHelper(startupWindow);
68-
win32WindowHelper.SetWindowMinMaxSize(new Win32WindowHelper.POINT() { x = 500, y = 500 });
68+
win32WindowHelper.SetWindowMinMaxSize(new Win32WindowHelper.POINT() { x = 532, y = 500 });
6969

7070
#if DEBUG
7171
if (Debugger.IsAttached)

WinUIGallery/Controls/HeaderTile.xaml.cs

Lines changed: 0 additions & 66 deletions
This file was deleted.
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<UserControl
3+
x:Class="WinUIGallery.Controls.HomePageHeader"
4+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:local="using:WinUIGallery.Controls"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
mc:Ignorable="d">
10+
<UserControl.Resources>
11+
<ResourceDictionary>
12+
<ResourceDictionary.ThemeDictionaries>
13+
<ResourceDictionary x:Key="Light">
14+
<ImageSource x:Key="StoreIcon">/Assets/HomeHeaderTiles/Header-Store.light.png</ImageSource>
15+
<LinearGradientBrush x:Name="BackgroundGradient" StartPoint="0.5,0" EndPoint="0.5,1">
16+
<GradientStop Offset="0.0" Color="#CED8E4" />
17+
<GradientStop Offset="1.0" Color="#D5DBE3" />
18+
</LinearGradientBrush>
19+
<x:Double x:Key="ImageOpacity">0.9</x:Double>
20+
<LinearGradientBrush x:Key="OverlayRadialGradient" StartPoint="0.5,0" EndPoint="0.5,1">
21+
<GradientStop Offset="0" Color="#FFFFFFFF" />
22+
<GradientStop Offset="0.75" Color="#FFFFFFFF" />
23+
<GradientStop Offset="0.85" Color="#00FFFFFF" />
24+
<GradientStop Offset="1" Color="#00FFFFFF" />
25+
</LinearGradientBrush>
26+
</ResourceDictionary>
27+
<ResourceDictionary x:Key="Dark">
28+
<ImageSource x:Key="StoreIcon">/Assets/HomeHeaderTiles/Header-Store.dark.png</ImageSource>
29+
<SolidColorBrush x:Key="BackgroundGradient" Color="#020B20" />
30+
<x:Double x:Key="ImageOpacity">0.8</x:Double>
31+
<LinearGradientBrush x:Key="OverlayRadialGradient" StartPoint="0.5,0" EndPoint="0.5,1">
32+
<GradientStop Offset="0" Color="#FF000000" />
33+
<GradientStop Offset="0.75" Color="#FF000000" />
34+
<GradientStop Offset="0.85" Color="#00000000" />
35+
<GradientStop Offset="1" Color="#00000000" />
36+
</LinearGradientBrush>
37+
</ResourceDictionary>
38+
<ResourceDictionary x:Key="HighContrast">
39+
<ImageSource x:Key="StoreIcon">/Assets/HomeHeaderTiles/Header-Store.dark.png</ImageSource>
40+
<SolidColorBrush x:Key="BackgroundGradient" Color="Black" />
41+
<x:Double x:Key="ImageOpacity">0.8</x:Double>
42+
<LinearGradientBrush x:Key="OverlayRadialGradient" StartPoint="0.5,0" EndPoint="0.5,1">
43+
<GradientStop Offset="0" Color="#FF000000" />
44+
<GradientStop Offset="0.55" Color="#FF000000" />
45+
<GradientStop Offset="0.95" Color="#00000000" />
46+
</LinearGradientBrush>
47+
</ResourceDictionary>
48+
</ResourceDictionary.ThemeDictionaries>
49+
</ResourceDictionary>
50+
</UserControl.Resources>
51+
<Grid x:Name="HeaderGrid" Margin="0">
52+
<Grid.RowDefinitions>
53+
<RowDefinition Height="Auto" />
54+
<RowDefinition Height="Auto" />
55+
<RowDefinition Height="*" />
56+
</Grid.RowDefinitions>
57+
<Grid>
58+
<Grid.RowDefinitions>
59+
<RowDefinition Height="Auto" />
60+
<RowDefinition Height="Auto" />
61+
<RowDefinition Height="*" />
62+
</Grid.RowDefinitions>
63+
64+
<local:OpacityMaskView
65+
Grid.RowSpan="3"
66+
Height="400"
67+
VerticalAlignment="Stretch">
68+
<local:OpacityMaskView.OpacityMask>
69+
<Rectangle Fill="{ThemeResource OverlayRadialGradient}" />
70+
</local:OpacityMaskView.OpacityMask>
71+
<Grid
72+
x:Name="ImageGrid"
73+
Margin="0,-100,0,0"
74+
Background="{ThemeResource BackgroundGradient}">
75+
<Image
76+
x:Name="HeroImage"
77+
Opacity="{ThemeResource ImageOpacity}"
78+
Source="/Assets/GalleryHeaderImage.png"
79+
Stretch="UniformToFill" />
80+
</Grid>
81+
82+
</local:OpacityMaskView>
83+
<TextBlock AutomationProperties.AutomationId="__ClickableAreaTextBlock" />
84+
<StackPanel
85+
Margin="36,48,0,0"
86+
VerticalAlignment="Center"
87+
Orientation="Vertical">
88+
<TextBlock
89+
x:Name="smallHeaderSubtitleText"
90+
FontSize="18"
91+
Text="{x:Bind WinAppSdkDetails}" />
92+
<TextBlock
93+
x:Name="smallHeaderText"
94+
Style="{StaticResource TitleLargeTextBlockStyle}"
95+
Text="{StaticResource AppTitleName}" />
96+
</StackPanel>
97+
98+
<local:HorizontalScrollContainer Grid.Row="2" Margin="0,56,0,0">
99+
<local:HorizontalScrollContainer.Source>
100+
<StackPanel Orientation="Horizontal" Spacing="12">
101+
<local:Tile
102+
Title="Getting started"
103+
Description="Get started with WinUI and explore detailed documentation."
104+
Link="https://learn.microsoft.com/windows/apps/get-started/">
105+
<local:Tile.Source>
106+
<Image Source="/Assets/HomeHeaderTiles/Header-WinUI.png" />
107+
</local:Tile.Source>
108+
</local:Tile>
109+
<local:Tile
110+
Title="Design"
111+
Description="Guidelines and toolkits for creating stunning WinUI experiences."
112+
Link="https://learn.microsoft.com/windows/apps/design/">
113+
<local:Tile.Source>
114+
<Image Source="/Assets/HomeHeaderTiles/Header-WindowsDesign.png" />
115+
</local:Tile.Source>
116+
</local:Tile>
117+
<local:Tile
118+
Title="WinUI on GitHub"
119+
Description="Explore the WinUI source code and repository."
120+
Link="https://github.com/microsoft/microsoft-ui-xaml">
121+
<local:Tile.Source>
122+
<Viewbox>
123+
<PathIcon Data="{StaticResource GitHubIconPath}" Foreground="{ThemeResource TextFillColorPrimaryBrush}" />
124+
</Viewbox>
125+
</local:Tile.Source>
126+
</local:Tile>
127+
<local:Tile
128+
Title="Community Toolkit"
129+
Description="A collection of helper functions, controls, and app services."
130+
Link="https://apps.microsoft.com/store/detail/windows-community-toolkit-sample-app/9NBLGGH4TLCQ">
131+
<local:Tile.Source>
132+
<Image Source="/Assets/HomeHeaderTiles/Header-Toolkit.png" />
133+
</local:Tile.Source>
134+
</local:Tile>
135+
<local:Tile
136+
Title="Code samples"
137+
Description="Find samples that demonstrate specific tasks, features, and APIs."
138+
Link="https://learn.microsoft.com/windows/apps/get-started/samples">
139+
<local:Tile.Source>
140+
<FontIcon
141+
Margin="0,8,0,0"
142+
FontSize="24"
143+
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
144+
Glyph="&#xE943;" />
145+
</local:Tile.Source>
146+
</local:Tile>
147+
<local:Tile
148+
Title="Partner Center"
149+
Description="Upload your app to the Store."
150+
Link="https://developer.microsoft.com/windows/">
151+
<local:Tile.Source>
152+
<Image Source="{ThemeResource StoreIcon}" />
153+
</local:Tile.Source>
154+
</local:Tile>
155+
</StackPanel>
156+
</local:HorizontalScrollContainer.Source>
157+
</local:HorizontalScrollContainer>
158+
</Grid>
159+
</Grid>
160+
</UserControl>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.UI.Xaml.Controls;
5+
using WinUIGallery.Helpers;
6+
7+
namespace WinUIGallery.Controls;
8+
9+
public sealed partial class HomePageHeader : UserControl
10+
{
11+
public string WinAppSdkDetails => VersionHelper.WinAppSdkDetails;
12+
13+
public HomePageHeader()
14+
{
15+
InitializeComponent();
16+
}
17+
}

WinUIGallery/Controls/HeaderTile.xaml renamed to WinUIGallery/Controls/HomePage/Tile.xaml

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<UserControl
2-
x:Class="WinUIGallery.Controls.HeaderTile"
2+
x:Class="WinUIGallery.Controls.Tile"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:local="using:WinUIGallery.Controls"
77
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8-
Width="220"
9-
Height="216"
8+
Width="232"
9+
Height="172"
1010
mc:Ignorable="d">
1111

1212
<Grid
@@ -45,42 +45,40 @@
4545
VerticalContentAlignment="Stretch"
4646
AutomationProperties.LabeledBy="{Binding ElementName=TitleText}"
4747
CornerRadius="{StaticResource OverlayCornerRadius}"
48-
NavigateUri="{x:Bind Link, Mode=OneWay}">
48+
NavigateUri="{x:Bind Link}">
4949
<Grid
5050
Padding="24"
5151
VerticalAlignment="Stretch"
5252
RowSpacing="16">
5353
<Grid.RowDefinitions>
54-
<RowDefinition Height="56" />
54+
<RowDefinition Height="36" />
5555
<RowDefinition Height="*" />
5656
</Grid.RowDefinitions>
5757
<FontIcon
5858
Grid.RowSpan="3"
5959
Margin="-12"
6060
HorizontalAlignment="Right"
6161
VerticalAlignment="Bottom"
62-
FontSize="16"
63-
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
62+
FontSize="14"
63+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
6464
Glyph="&#xE8A7;" />
6565
<ContentPresenter
6666
HorizontalAlignment="Left"
6767
VerticalAlignment="Top"
68-
Content="{x:Bind Source, Mode=OneWay}" />
69-
68+
Content="{x:Bind Source}" />
7069
<StackPanel
7170
Grid.Row="1"
7271
Orientation="Vertical"
7372
Spacing="4">
7473
<TextBlock
7574
x:Name="TitleText"
76-
FontSize="18"
7775
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
78-
Style="{StaticResource BodyTextBlockStyle}"
79-
Text="{x:Bind Title, Mode=OneWay}" />
76+
Style="{StaticResource BodyStrongTextBlockStyle}"
77+
Text="{x:Bind Title}" />
8078
<TextBlock
8179
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
8280
Style="{StaticResource CaptionTextBlockStyle}"
83-
Text="{x:Bind Description, Mode=OneWay}" />
81+
Text="{x:Bind Description}" />
8482
</StackPanel>
8583
</Grid>
8684
</HyperlinkButton>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) Microsoft Corporation and Contributors.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.UI.Xaml;
5+
using Microsoft.UI.Xaml.Controls;
6+
7+
namespace WinUIGallery.Controls;
8+
9+
public sealed partial class Tile : UserControl
10+
{
11+
public string Title
12+
{
13+
get { return (string)GetValue(TitleProperty); }
14+
set { SetValue(TitleProperty, value); }
15+
}
16+
17+
public static readonly DependencyProperty TitleProperty =
18+
DependencyProperty.Register(nameof(Title), typeof(string), typeof(Tile), new PropertyMetadata(null));
19+
20+
public string Description
21+
{
22+
get { return (string)GetValue(DescriptionProperty); }
23+
set { SetValue(DescriptionProperty, value); }
24+
}
25+
26+
public static readonly DependencyProperty DescriptionProperty =
27+
DependencyProperty.Register(nameof(Description), typeof(string), typeof(Tile), new PropertyMetadata(null));
28+
29+
public object Source
30+
{
31+
get { return (object)GetValue(SourceProperty); }
32+
set { SetValue(SourceProperty, value); }
33+
}
34+
35+
public static readonly DependencyProperty SourceProperty =
36+
DependencyProperty.Register(nameof(Source), typeof(object), typeof(Tile), new PropertyMetadata(null));
37+
38+
public string Link
39+
{
40+
get { return (string)GetValue(LinkProperty); }
41+
set { SetValue(LinkProperty, value); }
42+
}
43+
44+
public static readonly DependencyProperty LinkProperty =
45+
DependencyProperty.Register(nameof(Link), typeof(string), typeof(Tile), new PropertyMetadata(null));
46+
47+
48+
public Tile()
49+
{
50+
this.InitializeComponent();
51+
}
52+
}

0 commit comments

Comments
 (0)