Skip to content

Commit 0079b1f

Browse files
authored
Merge pull request #46 from TheJoeFin/favorite-songs-and-playlist
Favorite songs and playlist
2 parents 679fe37 + 1a04869 commit 0079b1f

39 files changed

+2897
-611
lines changed

Trdo/App.xaml.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
using System.ComponentModel;
66
using System.Threading;
77
using System.Threading.Tasks;
8+
using Trdo.Controls;
89
using Trdo.Pages;
10+
using Trdo.Services;
911
using Trdo.ViewModels;
1012
using Windows.UI;
1113
using Windows.UI.ViewManagement;
@@ -36,10 +38,21 @@ public App()
3638
InitializeComponent();
3739
_playerVm.PropertyChanged += PlayerVmOnPropertyChanged;
3840

41+
// Initialize PlaylistHistoryService early so it captures metadata from the start
42+
PlaylistHistoryService.EnsureInitialized();
43+
3944
// Subscribe to theme change events
4045
_uiSettings.ColorValuesChanged += OnColorValuesChanged;
4146
}
4247

48+
public void TryShowFlyout()
49+
{
50+
if (_trayIcon is null)
51+
return;
52+
53+
// TODO: find a way to programmatically show the flyout on the Icon
54+
}
55+
4356
protected override async void OnLaunched(LaunchActivatedEventArgs args)
4457
{
4558
// Check for single instance using a named mutex
@@ -131,6 +144,13 @@ private void InitializeTrayIcon()
131144
_trayIcon.Selected += TrayIcon_Selected;
132145
_trayIcon.ContextMenu += TrayIcon_ContextMenu;
133146
_trayIcon.IsVisible = true;
147+
148+
// Only show tutorial window on first run
149+
if (SettingsService.IsFirstRun)
150+
{
151+
TutorialWindow tutorialWindow = new();
152+
tutorialWindow.Show();
153+
}
134154
}
135155

136156
private void TrayIcon_ContextMenu(TrayIcon sender, TrayIconEventArgs args)

Trdo/Assets/Tutorial.gif

3.91 MB
Loading

Trdo/Controls/TutorialWindow.xaml

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ex:WindowEx
3+
x:Class="Trdo.Controls.TutorialWindow"
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:ex="using:WinUIEx"
8+
xmlns:local="using:Trdo.Controls"
9+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
10+
Title="Trdo First Run Window"
11+
Width="400"
12+
Height="600"
13+
IsMaximizable="False"
14+
IsMinimizable="False"
15+
mc:Ignorable="d">
16+
17+
<ex:WindowEx.SystemBackdrop>
18+
<MicaBackdrop />
19+
</ex:WindowEx.SystemBackdrop>
20+
<Grid>
21+
<Grid.RowDefinitions>
22+
<RowDefinition Height="auto" />
23+
<RowDefinition Height="*" />
24+
<RowDefinition Height="auto" />
25+
</Grid.RowDefinitions>
26+
27+
<TitleBar x:Name="ModernTitlebar" Title="Trdo">
28+
<TitleBar.IconSource>
29+
<ImageIconSource ImageSource="/Assets/Radio.ico" />
30+
</TitleBar.IconSource>
31+
</TitleBar>
32+
33+
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
34+
<StackPanel
35+
Margin="32,24,32,24"
36+
Orientation="Vertical"
37+
Spacing="20">
38+
39+
<!-- Welcome Header with Icon -->
40+
<StackPanel
41+
HorizontalAlignment="Center"
42+
Orientation="Vertical"
43+
Spacing="12">
44+
<Image
45+
Width="64"
46+
Height="64"
47+
HorizontalAlignment="Center"
48+
Source="/Assets/Radio.ico" />
49+
<TextBlock
50+
HorizontalAlignment="Center"
51+
Style="{StaticResource TitleLargeTextBlockStyle}"
52+
Text="Welcome to Trdo!" />
53+
<TextBlock
54+
HorizontalAlignment="Center"
55+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
56+
Style="{StaticResource SubheaderTextBlockStyle}"
57+
Text="Your tiny tray radio for Windows"
58+
TextAlignment="Center" />
59+
</StackPanel>
60+
61+
<!-- Tutorial Steps -->
62+
<StackPanel
63+
Margin="0,8,0,0"
64+
Orientation="Vertical"
65+
Spacing="16">
66+
<TextBlock
67+
FontSize="18"
68+
Style="{StaticResource BodyStrongTextBlockStyle}"
69+
Text="Quick Start Guide" />
70+
71+
<!-- Step 1 -->
72+
<Border
73+
Padding="16"
74+
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
75+
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
76+
BorderThickness="1"
77+
CornerRadius="8">
78+
<Grid ColumnSpacing="16">
79+
<Grid.ColumnDefinitions>
80+
<ColumnDefinition Width="Auto" />
81+
<ColumnDefinition Width="*" />
82+
</Grid.ColumnDefinitions>
83+
<Border
84+
Grid.Column="0"
85+
Width="32"
86+
Height="32"
87+
VerticalAlignment="Top"
88+
Background="{ThemeResource AccentFillColorDefaultBrush}"
89+
CornerRadius="20">
90+
<TextBlock
91+
HorizontalAlignment="Center"
92+
VerticalAlignment="Center"
93+
FontSize="16"
94+
FontWeight="Bold"
95+
Foreground="White"
96+
Text="1" />
97+
</Border>
98+
<StackPanel
99+
Grid.Column="1"
100+
VerticalAlignment="Center"
101+
Orientation="Vertical"
102+
Spacing="4">
103+
<TextBlock FontWeight="SemiBold" Text="Pin the Tray Icon" />
104+
<TextBlock
105+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
106+
Text="Make sure the Trdo icon is always visible in your system tray"
107+
TextWrapping="Wrap" />
108+
</StackPanel>
109+
</Grid>
110+
</Border>
111+
112+
<!-- Step 2 -->
113+
<Border
114+
Padding="16"
115+
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
116+
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
117+
BorderThickness="1"
118+
CornerRadius="8">
119+
<Grid ColumnSpacing="16">
120+
<Grid.ColumnDefinitions>
121+
<ColumnDefinition Width="Auto" />
122+
<ColumnDefinition Width="*" />
123+
</Grid.ColumnDefinitions>
124+
<Border
125+
Grid.Column="0"
126+
Width="32"
127+
Height="32"
128+
VerticalAlignment="Top"
129+
Background="{ThemeResource AccentFillColorDefaultBrush}"
130+
CornerRadius="20">
131+
<TextBlock
132+
HorizontalAlignment="Center"
133+
VerticalAlignment="Center"
134+
FontSize="16"
135+
FontWeight="Bold"
136+
Foreground="White"
137+
Text="2" />
138+
</Border>
139+
<StackPanel
140+
Grid.Column="1"
141+
VerticalAlignment="Center"
142+
Orientation="Vertical"
143+
Spacing="4">
144+
<TextBlock FontWeight="SemiBold" Text="Left Click to Play/Pause" />
145+
<TextBlock
146+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
147+
Text="Quick and easy playback control at your fingertips"
148+
TextWrapping="Wrap" />
149+
</StackPanel>
150+
</Grid>
151+
</Border>
152+
153+
<!-- Step 3 -->
154+
<Border
155+
Padding="16"
156+
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
157+
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
158+
BorderThickness="1"
159+
CornerRadius="8">
160+
<Grid ColumnSpacing="16">
161+
<Grid.ColumnDefinitions>
162+
<ColumnDefinition Width="Auto" />
163+
<ColumnDefinition Width="*" />
164+
</Grid.ColumnDefinitions>
165+
<Border
166+
Grid.Column="0"
167+
Width="32"
168+
Height="32"
169+
VerticalAlignment="Top"
170+
Background="{ThemeResource AccentFillColorDefaultBrush}"
171+
CornerRadius="20">
172+
<TextBlock
173+
HorizontalAlignment="Center"
174+
VerticalAlignment="Center"
175+
FontSize="16"
176+
FontWeight="Bold"
177+
Foreground="White"
178+
Text="3" />
179+
</Border>
180+
<StackPanel
181+
Grid.Column="1"
182+
VerticalAlignment="Center"
183+
Orientation="Vertical"
184+
Spacing="4">
185+
<TextBlock FontWeight="SemiBold" Text="Right Click for More Options" />
186+
<TextBlock
187+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
188+
Text="Browse stations, adjust settings, and explore all features"
189+
TextWrapping="Wrap" />
190+
</StackPanel>
191+
</Grid>
192+
</Border>
193+
</StackPanel>
194+
195+
<!-- Tutorial GIF -->
196+
<Border
197+
Margin="0,8,0,0"
198+
Padding="8"
199+
Background="{ThemeResource LayerFillColorDefaultBrush}"
200+
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
201+
BorderThickness="1"
202+
CornerRadius="8">
203+
<Image
204+
HorizontalAlignment="Center"
205+
Source="/Assets/Tutorial.gif"
206+
Stretch="Uniform" />
207+
</Border>
208+
209+
<!-- Feature Highlights -->
210+
<StackPanel
211+
Margin="0,8,0,0"
212+
Orientation="Vertical"
213+
Spacing="8">
214+
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="✨ What makes Trdo special:" />
215+
<TextBlock
216+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
217+
Text="• Lightweight and minimalistic design"
218+
TextWrapping="Wrap" />
219+
<TextBlock
220+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
221+
Text="• Access thousands of radio stations worldwide"
222+
TextWrapping="Wrap" />
223+
<TextBlock
224+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
225+
Text="• Beautiful Mica backdrop and modern UI"
226+
TextWrapping="Wrap" />
227+
<TextBlock
228+
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
229+
Text="• Lives quietly in your system tray"
230+
TextWrapping="Wrap" />
231+
</StackPanel>
232+
</StackPanel>
233+
</ScrollViewer>
234+
235+
<!-- Bottom Action Button -->
236+
<Border
237+
Grid.Row="2"
238+
Padding="32,16,32,20"
239+
Background="{ThemeResource LayerFillColorDefaultBrush}"
240+
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
241+
BorderThickness="0,1,0,0">
242+
<Button
243+
Padding="16,8"
244+
HorizontalAlignment="Stretch"
245+
Click="Button_Click"
246+
FontSize="16"
247+
Style="{StaticResource AccentButtonStyle}">
248+
<StackPanel Orientation="Horizontal" Spacing="8">
249+
<TextBlock FontSize="18" Text="🚀" />
250+
<TextBlock FontWeight="SemiBold" Text="Let's Get Started!" />
251+
</StackPanel>
252+
</Button>
253+
</Border>
254+
255+
</Grid>
256+
257+
</ex:WindowEx>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Trdo.Services;
2+
using WinUIEx;
3+
4+
namespace Trdo.Controls;
5+
/// <summary>
6+
/// An empty window that can be used on its own or navigated to within a Frame.
7+
/// </summary>
8+
public sealed partial class TutorialWindow : WindowEx
9+
{
10+
public TutorialWindow()
11+
{
12+
InitializeComponent();
13+
14+
ExtendsContentIntoTitleBar = true;
15+
SetTitleBar(ModernTitlebar);
16+
}
17+
18+
private void Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
19+
{
20+
// Mark first run as complete
21+
SettingsService.MarkFirstRunComplete();
22+
23+
Close();
24+
25+
if (App.Current is App currentApp)
26+
currentApp.TryShowFlyout();
27+
}
28+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.UI.Xaml.Data;
2+
using System;
3+
4+
namespace Trdo.Converters;
5+
6+
/// <summary>
7+
/// Converts a boolean favorite status to the appropriate star glyph.
8+
/// </summary>
9+
public class BooleanToFavoriteGlyphConverter : IValueConverter
10+
{
11+
/// <summary>
12+
/// Filled star glyph (favorited).
13+
/// </summary>
14+
private const string FilledStar = "\uE735";
15+
16+
/// <summary>
17+
/// Outline star glyph (not favorited).
18+
/// </summary>
19+
private const string OutlineStar = "\uE734";
20+
21+
public object Convert(object value, Type targetType, object parameter, string language)
22+
{
23+
if (value is bool isFavorited)
24+
{
25+
return isFavorited ? FilledStar : OutlineStar;
26+
}
27+
28+
return OutlineStar;
29+
}
30+
31+
public object ConvertBack(object value, Type targetType, object parameter, string language)
32+
{
33+
throw new NotImplementedException();
34+
}
35+
}

Trdo/Converters/NullToVisibilityConverter.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55
namespace Trdo.Converters;
66

77
/// <summary>
8-
/// Converts null to Visibility. Returns Visible when value is not null, Collapsed when null.
8+
/// Converts null or empty string to Visibility. Returns Visible when value is not null/empty, Collapsed when null/empty.
99
/// </summary>
1010
public class NullToVisibilityConverter : IValueConverter
1111
{
1212
public object Convert(object value, Type targetType, object parameter, string language)
1313
{
14-
return value != null ? Visibility.Visible : Visibility.Collapsed;
14+
if (value == null)
15+
return Visibility.Collapsed;
16+
17+
if (value is string str)
18+
return string.IsNullOrWhiteSpace(str) ? Visibility.Collapsed : Visibility.Visible;
19+
20+
return Visibility.Visible;
1521
}
1622

1723
public object ConvertBack(object value, Type targetType, object parameter, string language)

0 commit comments

Comments
 (0)