Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Trdo/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Trdo.Pages;
using Trdo.Services;
using Trdo.ViewModels;
using Windows.UI;
using Windows.UI.ViewManagement;
using WinUIEx;

Expand All @@ -27,7 +26,7 @@
private readonly UISettings _uiSettings = new();
private Mutex? _singleInstanceMutex;
private EventWaitHandle? _trayIconRestoreEvent;
private DispatcherQueueTimer? _trayIconWatchdogTimer;

Check warning on line 29 in Trdo/App.xaml.cs

View workflow job for this annotation

GitHub Actions / build

The field 'App._trayIconWatchdogTimer' is never used
private DispatcherQueueTimer? _restoreEventMonitorTimer;

/// <summary>
Expand Down Expand Up @@ -157,6 +156,7 @@

private void TrayIcon_ContextMenu(TrayIcon sender, TrayIconEventArgs args)
{
WindowPlacementService.CapturePointerAnchor();
args.Flyout = CreateFlyout();
}

Expand All @@ -166,6 +166,7 @@
if (!_playerVm.CanPlay)
{
// No stations available, show the flyout to encourage user to add a station
WindowPlacementService.CapturePointerAnchor();
args.Flyout = CreateFlyout();
return;
}
Expand All @@ -190,6 +191,7 @@

flyout.Opened += (s, e) =>
{
WindowPlacementService.CapturePointerAnchor();
// Clear the back stack when flyout opens to prevent accumulation
Services.NavigationService.Instance.ClearBackStack();
};
Expand Down Expand Up @@ -272,7 +274,7 @@
}
else if (_playerVm.IsPlaying)
{

// Include now playing info if available
if (_playerVm.HasNowPlaying)
{
Expand Down
123 changes: 123 additions & 0 deletions Trdo/Controls/ManualStationWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8" ?>
<ex:WindowEx
x:Class="Trdo.Controls.ManualStationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ex="using:WinUIEx"
xmlns:local="using:Trdo.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Trdo - Add Station"
Width="400"
Height="500"
IsMaximizable="False"
IsMinimizable="False"
mc:Ignorable="d">

<ex:WindowEx.SystemBackdrop>
<MicaBackdrop />
</ex:WindowEx.SystemBackdrop>

<Grid RowDefinitions="Auto,*,Auto">

<TitleBar x:Name="ModernTitlebar" Title="{x:Bind ViewModel.PageTitle, Mode=OneWay}">
<TitleBar.IconSource>
<ImageIconSource ImageSource="/Assets/Radio.ico" />
</TitleBar.IconSource>
</TitleBar>

<!-- Content Area -->
<ScrollView Grid.Row="1" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="24,16,24,16" Spacing="12">

<!-- Station Name Input -->
<StackPanel Spacing="4">
<TextBlock FontWeight="SemiBold" Text="Station Name" />
<TextBox
x:Name="StationNameTextBox"
PlaceholderText="e.g., WYMS - Hometown radio"
Text="{x:Bind ViewModel.StationName,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>

<!-- Stream URL Input -->
<StackPanel Spacing="4">
<TextBlock FontWeight="SemiBold" Text="Stream URL" />
<TextBox
x:Name="StreamUrlTextBox"
PlaceholderText="e.g., https://example.com/stream"
Text="{x:Bind ViewModel.StreamUrl,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</StackPanel>

<!-- Homepage URL Input -->
<StackPanel Spacing="4">
<TextBlock FontWeight="SemiBold" Text="Homepage (Optional)" />
<TextBox
x:Name="HomepageTextBox"
PlaceholderText="e.g., https://example.com"
Text="{x:Bind ViewModel.Homepage,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</StackPanel>

<!-- Favicon URL Input -->
<StackPanel Spacing="4">
<TextBlock FontWeight="SemiBold" Text="Station Logo/Icon URL (Optional)" />
<TextBox
x:Name="FaviconUrlTextBox"
PlaceholderText="e.g., https://example.com/logo.png"
Text="{x:Bind ViewModel.FaviconUrl,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
</StackPanel>

</StackPanel>
</ScrollView>

<!-- Buttons -->
<Border
Grid.Row="2"
Padding="24,12,24,16"
Background="{ThemeResource LayerFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="0,1,0,0">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Button
Grid.Column="0"
HorizontalAlignment="Stretch"
Click="CancelButton_Click">
<StackPanel Orientation="Horizontal" Spacing="8">
<FontIcon FontSize="16" Glyph="&#xE711;" />
<TextBlock Text="Cancel" />
</StackPanel>
</Button>

<Button
Grid.Column="1"
HorizontalAlignment="Stretch"
Click="SaveButton_Click"
IsEnabled="{x:Bind ViewModel.CanSave,
Mode=OneWay}"
Style="{StaticResource AccentButtonStyle}">
<StackPanel Orientation="Horizontal" Spacing="8">
<FontIcon FontSize="16" Glyph="&#xE74E;" />
<TextBlock Text="Save" />
</StackPanel>
</Button>
</Grid>
</Border>

</Grid>

</ex:WindowEx>
60 changes: 60 additions & 0 deletions Trdo/Controls/ManualStationWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Trdo.Models;
using Trdo.Services;
using Trdo.ViewModels;
using WinUIEx;

namespace Trdo.Controls;

/// <summary>
/// A small standalone window for manually adding or editing a radio station.
/// Opens as a pop-out window so that closing the tray flyout does not clear the form fields.
/// </summary>
public sealed partial class ManualStationWindow : WindowEx
{
public AddStationViewModel ViewModel { get; }

public ManualStationWindow()
{
InitializeComponent();

ViewModel = new AddStationViewModel();
ViewModel.SetPlayerViewModel(PlayerViewModel.Shared);

ExtendsContentIntoTitleBar = true;
SetTitleBar(ModernTitlebar);

Activated += ManualStationWindow_Activated;
}

/// <summary>
/// Opens the window pre-filled with the given station's data for editing.
/// </summary>
public void LoadStationForEdit(RadioStation station)
{
ViewModel.LoadStationForEdit(station);
}

private void ManualStationWindow_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args)
{
// Focus the station name field once the window is ready
if (args.WindowActivationState != Microsoft.UI.Xaml.WindowActivationState.Deactivated)
{
WindowPlacementService.PositionWindowNearAnchor(this, 400, 500);
StationNameTextBox.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
Activated -= ManualStationWindow_Activated;
}
}

private void SaveButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
if (ViewModel.Save())
{
Close();
}
}

private void CancelButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
Close();
}
}
10 changes: 10 additions & 0 deletions Trdo/Controls/TutorialWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ public TutorialWindow()

ExtendsContentIntoTitleBar = true;
SetTitleBar(ModernTitlebar);
Activated += TutorialWindow_Activated;
}

private void TutorialWindow_Activated(object sender, Microsoft.UI.Xaml.WindowActivatedEventArgs args)
{
if (args.WindowActivationState == Microsoft.UI.Xaml.WindowActivationState.Deactivated)
return;

WindowPlacementService.PositionWindowNearAnchor(this, 400, 600);
Activated -= TutorialWindow_Activated;
}

private void Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
Expand Down
19 changes: 11 additions & 8 deletions Trdo/Pages/PlayingPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Trdo.Models;
using Trdo.Services;
using Trdo.ViewModels;
using WinUIEx;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
Expand All @@ -23,9 +22,9 @@
private const int MinIndexForScrolling = 3;
private const string FilledStar = "\uE735";
private const string OutlineStar = "\uE734";

private readonly FavoritesService _favoritesService = FavoritesService.Instance;

public PlayerViewModel ViewModel { get; }
private ShellViewModel? _shellViewModel;

Expand Down Expand Up @@ -117,7 +116,7 @@
UpdatePlayButtonState();
UpdateStationSelection();

if (e.PropertyName == nameof(PlayerViewModel.CurrentMetadata) ||
if (e.PropertyName == nameof(PlayerViewModel.CurrentMetadata) ||
e.PropertyName == nameof(PlayerViewModel.HasNowPlaying))
{
UpdateFavoriteButtonState();
Expand Down Expand Up @@ -321,7 +320,7 @@
private void FavoriteButton_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("[PlayingPage] Favorite button clicked");

if (ViewModel.CurrentMetadata?.HasMetadata != true)
{
Debug.WriteLine("[PlayingPage] No metadata to favorite");
Expand All @@ -331,7 +330,7 @@
string stationName = ViewModel.SelectedStation?.Name ?? "Unknown Station";
bool isFavorited = _favoritesService.ToggleFavorite(ViewModel.CurrentMetadata, stationName);
Debug.WriteLine($"[PlayingPage] Track favorite toggled. IsFavorited: {isFavorited}");

// UpdateFavoriteButtonState will be called via the FavoritesChanged event
}

Expand All @@ -347,7 +346,7 @@
{
Debug.WriteLine($"[PlayingPage] Visit Station Site clicked: {station.Name}");
// Navigate to AddStation page in edit mode with the station data
ViewModel.VisitWebsite(station);

Check warning on line 349 in Trdo/Pages/PlayingPage.xaml.cs

View workflow job for this annotation

GitHub Actions / build

Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
}
}

Expand All @@ -356,8 +355,12 @@
if (sender is MenuFlyoutItem menuItem && menuItem.Tag is RadioStation station)
{
Debug.WriteLine($"[PlayingPage] Edit station clicked: {station.Name}");
// Navigate to AddStation page in edit mode with the station data
_shellViewModel?.NavigateToAddStationPage(station);
// Open a pop-out window for editing so the flyout closing doesn't clear the fields
WindowPlacementService.CapturePointerAnchor();
ManualStationWindow editWindow = new();
WindowHelper.Track(editWindow);
editWindow.LoadStationForEdit(station);
editWindow.Activate();
}
}

Expand Down
9 changes: 6 additions & 3 deletions Trdo/Pages/SearchStation.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using System;
using Trdo.Controls;
using Trdo.Models;
using Trdo.Services;
using Trdo.ViewModels;
Expand Down Expand Up @@ -139,8 +139,11 @@ private void AddStationButton_Click(object sender, RoutedEventArgs e)
private void ManualEntryButton_Click(object sender, RoutedEventArgs e)
{
StopPreview();
// Navigate to manual entry page
_shellViewModel?.NavigateToAddStationPage();
// Open a pop-out window for manual station entry so the flyout closing doesn't clear the fields
WindowPlacementService.CapturePointerAnchor();
ManualStationWindow addWindow = new();
WindowHelper.Track(addWindow);
addWindow.Activate();
}

private void CancelButton_Click(object sender, RoutedEventArgs e)
Expand Down
Loading
Loading