Skip to content
Draft
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
84 changes: 64 additions & 20 deletions Screenbox/Behaviors/AddToPlaylistFlyoutBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,28 @@ public MenuFlyoutSubItem? TargetSubItem

private readonly PlaylistsContext _playlistsContext;
private FrameworkElement? _flyoutTarget;
private readonly MenuFlyoutItem _createNewPlaylistItem;
private readonly MenuFlyoutSeparator _separator = new();
private readonly MenuFlyoutItem _noPlaylistsItem;
private readonly List<MenuFlyoutItem> _playlistItems = new();

public AddToPlaylistFlyoutBehavior()
{
_playlistsContext = Ioc.Default.GetRequiredService<PlaylistsContext>();
CreatePlaylistCommand = new AsyncRelayCommand<IEnumerable<MediaViewModel>>(CreatePlaylistAsync);

_createNewPlaylistItem = new MenuFlyoutItem
{
Icon = new SymbolIcon(Symbol.Add),
Text = Strings.Resources.CreateNewPlaylist,
Command = CreatePlaylistCommand
};

_noPlaylistsItem = new MenuFlyoutItem
{
Text = Strings.Resources.NoPlaylists,
IsEnabled = false
};
}

protected override void OnAttached()
Expand Down Expand Up @@ -106,35 +123,62 @@ private void PopulateMenu()
_ => [],
};

menuItems.Clear();
menuItems.Add(new MenuFlyoutItem
{
Icon = new SymbolIcon(Symbol.Add),
Text = Strings.Resources.CreateNewPlaylist,
Command = CreatePlaylistCommand,
CommandParameter = contextItems
});
_createNewPlaylistItem.CommandParameter = contextItems;

menuItems.Add(new MenuFlyoutSeparator());
var playlists = _playlistsContext.Playlists.Where(p => p is not null).ToList();

if (_playlistsContext.Playlists.Count == 0)
if (playlists.Count == 0)
{
menuItems.Add(new MenuFlyoutItem
if (menuItems.Count != 3 || menuItems[0] != _createNewPlaylistItem || menuItems[2] != _noPlaylistsItem)
{
Text = Strings.Resources.NoPlaylists,
IsEnabled = false
});
menuItems.Clear();
menuItems.Add(_createNewPlaylistItem);
menuItems.Add(_separator);
menuItems.Add(_noPlaylistsItem);
}
return;
}

foreach (var playlist in _playlistsContext.Playlists.Where(p => p is not null))
while (_playlistItems.Count < playlists.Count)
{
menuItems.Add(new MenuFlyoutItem
_playlistItems.Add(new MenuFlyoutItem());
}

for (int i = 0; i < playlists.Count; i++)
{
var playlist = playlists[i];
var item = _playlistItems[i];
item.Text = playlist.Name;
item.Command = playlist.AddItemsCommand;
item.CommandParameter = contextItems;
}

int expectedCount = 2 + playlists.Count;
bool needsRebuild = menuItems.Count != expectedCount ||
menuItems[0] != _createNewPlaylistItem ||
menuItems[1] != _separator;

if (!needsRebuild)
{
for (int i = 0; i < playlists.Count; i++)
{
Text = playlist.Name,
Command = playlist.AddItemsCommand,
CommandParameter = contextItems
});
if (menuItems[i + 2] != _playlistItems[i])
{
needsRebuild = true;
break;
}
}
}

if (needsRebuild)
{
menuItems.Clear();
menuItems.Add(_createNewPlaylistItem);
menuItems.Add(_separator);
for (int i = 0; i < playlists.Count; i++)
{
menuItems.Add(_playlistItems[i]);
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion Screenbox/Commands/SetPlaybackOptionsCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using Screenbox.Core.ViewModels;
using Screenbox.Dialogs;
Expand All @@ -10,7 +11,7 @@ internal sealed partial class SetPlaybackOptionsCommand : IRelayCommand
{
public event EventHandler? CanExecuteChanged;

public IRelayCommand? PlayCommand { get; set; }
public ICommand? PlayCommand { get; set; }

public bool CanExecute(object? parameter)
{
Expand Down
171 changes: 171 additions & 0 deletions Screenbox/Controls/MediaMenuFlyout.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using CommunityToolkit.WinUI;
using Microsoft.Xaml.Interactivity;
using Screenbox.Commands;
using Screenbox.Converters;
using Screenbox.Core.ViewModels;
using Screenbox.Helpers;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Screenbox.Strings;

namespace Screenbox.Controls;

public partial class MediaMenuFlyout : MenuFlyout
{
public static readonly DependencyProperty PlayCommandProperty = DependencyProperty.Register(
nameof(PlayCommand), typeof(ICommand), typeof(MediaMenuFlyout), new PropertyMetadata(null));
public ICommand PlayCommand { get => (ICommand)GetValue(PlayCommandProperty); set => SetValue(PlayCommandProperty, value); }

public static readonly DependencyProperty PlayNextCommandProperty = DependencyProperty.Register(
nameof(PlayNextCommand), typeof(ICommand), typeof(MediaMenuFlyout), new PropertyMetadata(null));
public ICommand PlayNextCommand { get => (ICommand)GetValue(PlayNextCommandProperty); set => SetValue(PlayNextCommandProperty, value); }

public static readonly DependencyProperty AddToQueueCommandProperty = DependencyProperty.Register(
nameof(AddToQueueCommand), typeof(ICommand), typeof(MediaMenuFlyout), new PropertyMetadata(null));
public ICommand AddToQueueCommand { get => (ICommand)GetValue(AddToQueueCommandProperty); set => SetValue(AddToQueueCommandProperty, value); }

public static readonly DependencyProperty ContextItemProperty = DependencyProperty.Register(
nameof(ContextItem), typeof(object), typeof(MediaMenuFlyout), new PropertyMetadata(null));
public object ContextItem { get => GetValue(ContextItemProperty); set => SetValue(ContextItemProperty, value); }

public static readonly DependencyProperty IsAdvancedModeEnabledProperty = DependencyProperty.Register(
nameof(IsAdvancedModeEnabled), typeof(bool), typeof(MediaMenuFlyout), new PropertyMetadata(false));
public bool IsAdvancedModeEnabled { get => (bool)GetValue(IsAdvancedModeEnabledProperty); set => SetValue(IsAdvancedModeEnabledProperty, value); }

private MenuFlyoutItem? _playItem;
private FontIcon? _playIcon;
private MenuFlyoutItem? _playNextItem;
private MenuFlyoutItem? _addToQueueItem;
private MenuFlyoutSubItem? _addToPlaylistSubItem;
private MenuFlyoutItem? _openWithItem;
private MenuFlyoutItem? _openInFileExplorerItem;
private MenuFlyoutItem? _propertiesItem;
private MenuFlyoutItem? _playbackOptionsItem;
private MenuFlyoutSeparator? _advancedSeparator;
private readonly SetPlaybackOptionsCommand _playbackOptionsCommand = new();
private bool _isInitialized;

private readonly List<MenuFlyoutItemBase> _extraItems = new();

public MediaMenuFlyout()
{
Opening += OnOpening;
}

private void EnsureInitialized()
{
if (_isInitialized) return;
_isInitialized = true;

_extraItems.AddRange(Items);
Items.Clear();

var symbolFont = (FontFamily)Application.Current.Resources["ScreenboxSymbolThemeFontFamily"];

_playIcon = new FontIcon { FontFamily = symbolFont };
_playItem = new MenuFlyoutItem { Icon = _playIcon };

var playNextIcon = new FontIcon { FontFamily = symbolFont, Glyph = (string)Application.Current.Resources["PlayAddGlyph"] };
_playNextItem = new MenuFlyoutItem { Icon = playNextIcon, Text = Resources.PlayNext };

string addToQueueGlyph = GlobalizationHelper.IsRightToLeftLanguage
? (string)Application.Current.Resources["PlaylistMusicAddMirroredGlyph"]
: (string)Application.Current.Resources["PlaylistMusicAddGlyph"];
var addToQueueIcon = new FontIcon { FontFamily = symbolFont, Glyph = addToQueueGlyph };
_addToQueueItem = new MenuFlyoutItem { Icon = addToQueueIcon, Text = Resources.AddToQueue };

string addToPlaylistGlyph = GlobalizationHelper.IsRightToLeftLanguage
? (string)Application.Current.Resources["PlaylistAddMirroredGlyph"]
: (string)Application.Current.Resources["PlaylistAddGlyph"];
var addToPlaylistIcon = new FontIcon { FontFamily = symbolFont, Glyph = addToPlaylistGlyph };
_addToPlaylistSubItem = new MenuFlyoutSubItem { Text = Resources.AddToPlaylist, Icon = addToPlaylistIcon };

Interaction.GetBehaviors(this).Add(new Screenbox.Behaviors.AddToPlaylistFlyoutBehavior { TargetSubItem = _addToPlaylistSubItem });

var openWithIcon = new FontIcon { Glyph = "\uE7AC", MirroredWhenRightToLeft = true };
_openWithItem = new MenuFlyoutItem { Icon = openWithIcon, Text = Resources.OpenWith, Command = (ICommand)Application.Current.Resources["OpenWithCommand"] };

var openInFileExplorerIcon = new FontIcon { Glyph = "\uEC50" };
_openInFileExplorerItem = new MenuFlyoutItem
{
Icon = openInFileExplorerIcon,
Text = Resources.OpenInFileExplorer,
Command = (ICommand)Application.Current.Resources["OpenInFileExplorerCommand"],
Visibility = DeviceInfoHelper.IsDesktop ? Visibility.Visible : Visibility.Collapsed
};

var propertiesIcon = new FontIcon { Glyph = "\uE946" };
_propertiesItem = new MenuFlyoutItem { Icon = propertiesIcon, Text = Resources.Properties, Command = (ICommand)Application.Current.Resources["ShowPropertiesCommand"] };

var settingsIcon = new SymbolIcon { Symbol = Symbol.Setting };
_playbackOptionsItem = new MenuFlyoutItem
{
Icon = settingsIcon,
Text = Resources.SetPlaybackOptions,
Command = _playbackOptionsCommand
};
_advancedSeparator = new MenuFlyoutSeparator();

Items.Add(_playItem);
Items.Add(_playNextItem);
Items.Add(_addToQueueItem);
Items.Add(new MenuFlyoutSeparator());
Items.Add(_addToPlaylistSubItem);
Items.Add(_openWithItem);
Items.Add(_openInFileExplorerItem);
Items.Add(_propertiesItem);

foreach (var extraItem in _extraItems)
{
Items.Add(extraItem);
}

Items.Add(_advancedSeparator);
Items.Add(_playbackOptionsItem);
}

private void OnOpening(object? sender, object e)
{
EnsureInitialized();

var mediaVm = ContextItem as MediaViewModel;
if (ContextItem is StorageItemViewModel storageItem)
{
mediaVm = storageItem.Media;
}

_playItem!.Command = PlayCommand;
_playItem!.CommandParameter = ContextItem;

_playNextItem!.Command = PlayNextCommand;
_playNextItem!.CommandParameter = ContextItem;

_addToQueueItem!.Command = AddToQueueCommand;
_addToQueueItem!.CommandParameter = ContextItem;

_openWithItem!.CommandParameter = mediaVm;
_openInFileExplorerItem!.CommandParameter = mediaVm;
_propertiesItem!.CommandParameter = mediaVm;

if (mediaVm != null)
{
_playItem!.Text = ItemLabelHelper.GetPlayPauseLabel(mediaVm.IsPlaying);
_playIcon!.Glyph = GlyphConverter.ToPlayPauseGlyph(mediaVm.IsPlaying);
}
else
{
_playItem!.Text = ItemLabelHelper.GetPlayPauseLabel(false);
_playIcon!.Glyph = GlyphConverter.ToPlayPauseGlyph(false);
}

_advancedSeparator!.Visibility = IsAdvancedModeEnabled ? Visibility.Visible : Visibility.Collapsed;
_playbackOptionsItem!.Visibility = IsAdvancedModeEnabled ? Visibility.Visible : Visibility.Collapsed;

_playbackOptionsItem!.CommandParameter = ContextItem;
_playbackOptionsCommand.PlayCommand = PlayCommand;
}
}
79 changes: 8 additions & 71 deletions Screenbox/Pages/AlbumDetailsPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,79 +26,20 @@

<commands:BindableCommand x:Key="PlayCommand" Command="{x:Bind ViewModel.PlayCommand}" />

<MenuFlyout x:Key="ItemFlyout">
<interactivity:Interaction.Behaviors>
<behaviors:AddToPlaylistFlyoutBehavior TargetSubItem="{x:Bind AddToPlaylistSubMenu}" />
</interactivity:Interaction.Behaviors>

<MenuFlyoutItem
Command="{x:Bind ViewModel.PlayCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Text="{x:Bind helpers:ItemLabelHelper.GetPlayPauseLabel(ViewModel.ContextMedia.IsPlaying), Mode=OneWay}">
<MenuFlyoutItem.Icon>
<FontIcon FontFamily="{StaticResource ScreenboxSymbolThemeFontFamily}" Glyph="{x:Bind converters:GlyphConverter.ToPlayPauseGlyph(ViewModel.ContextMedia.IsPlaying), Mode=OneWay}" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem
Command="{x:Bind Common.PlayNextCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Icon="{ui:FontIcon FontFamily={StaticResource ScreenboxSymbolThemeFontFamily},
Glyph={StaticResource PlayAddGlyph}}"
Text="{x:Bind strings:Resources.PlayNext}" />
<MenuFlyoutItem
Command="{x:Bind Common.AddToQueueCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Text="{x:Bind strings:Resources.AddToQueue}">
<MenuFlyoutItem.Icon>
<FontIcon
x:Name="AddToQueueMenuFlyoutItemIcon"
FontFamily="{StaticResource ScreenboxSymbolThemeFontFamily}"
Glyph="{StaticResource PlaylistMusicAddGlyph}" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutSeparator />
<MenuFlyoutSubItem x:Name="AddToPlaylistSubMenu" Text="{x:Bind strings:Resources.AddToPlaylist}">
<MenuFlyoutSubItem.Icon>
<FontIcon
x:Name="AddToPlaylistMenuFlyoutSubItemIcon"
FontFamily="{StaticResource ScreenboxSymbolThemeFontFamily}"
Glyph="{StaticResource PlaylistAddGlyph}" />
</MenuFlyoutSubItem.Icon>
</MenuFlyoutSubItem>
<MenuFlyoutItem
Command="{StaticResource OpenWithCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Icon="{ui:FontIcon Glyph=&#xE7AC;,
MirroredWhenRightToLeft=True}"
Text="{x:Bind strings:Resources.OpenWith}" />
<MenuFlyoutItem
Command="{StaticResource OpenInFileExplorerCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Icon="{ui:FontIcon Glyph=&#xEC50;}"
Text="{x:Bind strings:Resources.OpenInFileExplorer}"
Visibility="{x:Bind helpers:DeviceInfoHelper.IsDesktop}" />
<MenuFlyoutItem
Command="{StaticResource ShowPropertiesCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Icon="{ui:FontIcon Glyph=&#xE946;}"
Text="{x:Bind strings:Resources.Properties}" />
<controls:MediaMenuFlyout
x:Key="ItemFlyout"
AddToQueueCommand="{x:Bind Common.AddToQueueCommand}"
ContextItem="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
IsAdvancedModeEnabled="{x:Bind Common.IsAdvancedModeEnabled}"
PlayCommand="{x:Bind ViewModel.PlayCommand}"
PlayNextCommand="{x:Bind Common.PlayNextCommand}">
<MenuFlyoutItem
Command="{x:Bind Common.OpenArtistCommand}"
CommandParameter="{x:Bind ViewModel.ContextMedia.MainArtist, Mode=OneWay}"
Icon="{ui:FontIcon Glyph=&#xE77B;}"
Text="{x:Bind strings:Resources.ShowArtist}"
Visibility="{x:Bind ViewModel.ContextMedia.MainArtist, Converter={StaticResource EmptyObjectToVisibilityConverter}, Mode=OneWay}" />
<MenuFlyoutSeparator Visibility="{x:Bind Common.IsAdvancedModeEnabled}" />
<MenuFlyoutItem
CommandParameter="{x:Bind ViewModel.ContextMedia, Mode=OneWay}"
Icon="{ui:SymbolIcon Symbol=Setting}"
Text="{x:Bind strings:Resources.SetPlaybackOptions}"
Visibility="{x:Bind Common.IsAdvancedModeEnabled}">
<MenuFlyoutItem.Command>
<commands:SetPlaybackOptionsCommand PlayCommand="{x:Bind ViewModel.PlayCommand}" />
</MenuFlyoutItem.Command>
</MenuFlyoutItem>
</MenuFlyout>
</controls:MediaMenuFlyout>
</ResourceDictionary>
</Page.Resources>

Expand Down Expand Up @@ -320,10 +261,6 @@
<VisualState.StateTriggers>
<StateTrigger IsActive="{x:Bind helpers:GlobalizationHelper.IsRightToLeftLanguage}" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="AddToQueueMenuFlyoutItemIcon.Glyph" Value="{StaticResource PlaylistMusicAddMirroredGlyph}" />
<contract13NotPresent:Setter Target="AddToPlaylistMenuFlyoutSubItemIcon.Glyph" Value="{StaticResource PlaylistAddMirroredGlyph}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Expand Down
Loading