diff --git a/src/JellyBox/Behaviors/ListViewBaseCommandBehavior.cs b/src/JellyBox/Behaviors/ListViewBaseCommandBehavior.cs index 6936ef3..efa6568 100644 --- a/src/JellyBox/Behaviors/ListViewBaseCommandBehavior.cs +++ b/src/JellyBox/Behaviors/ListViewBaseCommandBehavior.cs @@ -1,27 +1,14 @@ -using System.Windows.Input; +using JellyBox.Models; using Microsoft.Xaml.Interactivity; -using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace JellyBox.Behaviors; /// -/// Creates an attached property for all ListViewBase controls allowing binding a command object to it's ItemClick event. +/// Invokes the NavigateCommand on INavigable items when they are clicked in a ListViewBase control. /// internal sealed class ListViewBaseCommandBehavior : Behavior { - public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( - "Command", - typeof(ICommand), - typeof(ListViewBaseCommandBehavior), - new PropertyMetadata(null)); - - public ICommand Command - { - get => (ICommand)GetValue(CommandProperty); - set => SetValue(CommandProperty, value); - } - protected override void OnAttached() { base.OnAttached(); @@ -36,12 +23,14 @@ protected override void OnDetaching() AssociatedObject.ItemClick -= ItemClicked; } - private void ItemClicked(object sender, ItemClickEventArgs e) + private static void ItemClicked(object sender, ItemClickEventArgs e) { - ICommand command = Command; - if (command is not null && command.CanExecute(e.ClickedItem)) + if (e.ClickedItem is INavigable navigable) { - command.Execute(e.ClickedItem); + if (navigable.NavigateCommand.CanExecute(null)) + { + navigable.NavigateCommand.Execute(null); + } } } } \ No newline at end of file diff --git a/src/JellyBox/Models/Card.cs b/src/JellyBox/Models/Card.cs index 0d6d9fe..71c596a 100644 --- a/src/JellyBox/Models/Card.cs +++ b/src/JellyBox/Models/Card.cs @@ -1,5 +1,5 @@ +using System.Windows.Input; using JellyBox.Services; -using Jellyfin.Sdk.Generated.Models; namespace JellyBox.Models; @@ -11,10 +11,8 @@ internal enum CardShape Banner, } -internal sealed record Card +internal sealed record Card : INavigable { - public required BaseItemDto Item { get; init; } - public required string Name { get; init; } public required int ImageWidth { get; init; } @@ -22,4 +20,6 @@ internal sealed record Card public required int ImageHeight { get; init; } public required JellyfinImage Image { get; init; } + + public required ICommand NavigateCommand { get; init; } } diff --git a/src/JellyBox/Models/CardFactory.cs b/src/JellyBox/Models/CardFactory.cs index 994eb10..742ef78 100644 --- a/src/JellyBox/Models/CardFactory.cs +++ b/src/JellyBox/Models/CardFactory.cs @@ -1,3 +1,4 @@ +using CommunityToolkit.Mvvm.Input; using JellyBox.Services; using Jellyfin.Sdk.Generated.Models; @@ -9,7 +10,8 @@ public static Card CreateFromItem( BaseItemDto item, CardShape shape, ImageType? preferredImageType, - JellyfinImageResolver imageResolver) + JellyfinImageResolver imageResolver, + NavigationManager navigationManager) { double aspectRatio = GetAspectRatio(shape); ImageType imageType; @@ -50,11 +52,11 @@ public static Card CreateFromItem( return new Card { - Item = item, Name = item.Name!, ImageWidth = imageWidth, ImageHeight = imageHeight, Image = image, + NavigateCommand = new RelayCommand(() => navigationManager.NavigateToItem(item)), }; } diff --git a/src/JellyBox/Models/INavigable.cs b/src/JellyBox/Models/INavigable.cs new file mode 100644 index 0000000..167adec --- /dev/null +++ b/src/JellyBox/Models/INavigable.cs @@ -0,0 +1,11 @@ +using System.Windows.Input; + +namespace JellyBox.Models; + +/// +/// Interface for UI models that support navigation when activated. +/// +internal interface INavigable +{ + ICommand NavigateCommand { get; } +} diff --git a/src/JellyBox/Models/Section.cs b/src/JellyBox/Models/Section.cs index 311cc7e..bea505b 100644 --- a/src/JellyBox/Models/Section.cs +++ b/src/JellyBox/Models/Section.cs @@ -1,5 +1,3 @@ -using System.Windows.Input; - namespace JellyBox.Models; internal sealed class Section @@ -7,6 +5,4 @@ internal sealed class Section public required string Name { get; set; } public required IReadOnlyList? Cards { get; set; } - - public required ICommand NavigateToCardCommand { get; set; } } \ No newline at end of file diff --git a/src/JellyBox/Resources/Templates.xaml b/src/JellyBox/Resources/Templates.xaml index a2bdda9..5496d5e 100644 --- a/src/JellyBox/Resources/Templates.xaml +++ b/src/JellyBox/Resources/Templates.xaml @@ -25,7 +25,7 @@ ScrollViewer.VerticalScrollMode="Disabled" SelectionMode="None"> - + diff --git a/src/JellyBox/ViewModels/HomeViewModel.cs b/src/JellyBox/ViewModels/HomeViewModel.cs index 24ae53f..7aa8bfd 100644 --- a/src/JellyBox/ViewModels/HomeViewModel.cs +++ b/src/JellyBox/ViewModels/HomeViewModel.cs @@ -1,6 +1,5 @@ using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using JellyBox.Models; using JellyBox.Services; using Jellyfin.Sdk; @@ -104,20 +103,13 @@ public async void Initialize() continue; } - cards.Add(CardFactory.CreateFromItem(item, cardShape, preferredImageType, _imageResolver)); + cards.Add(CardFactory.CreateFromItem(item, cardShape, preferredImageType, _imageResolver, _navigationManager)); } return new Section { Name = name, Cards = cards, - NavigateToCardCommand = NavigateToCardCommand, }; } - - [RelayCommand] - private void NavigateToCard(Card card) - { - _navigationManager.NavigateToItem(card.Item); - } } \ No newline at end of file diff --git a/src/JellyBox/ViewModels/ItemDetailsViewModel.cs b/src/JellyBox/ViewModels/ItemDetailsViewModel.cs index 7980cff..dc550ee 100644 --- a/src/JellyBox/ViewModels/ItemDetailsViewModel.cs +++ b/src/JellyBox/ViewModels/ItemDetailsViewModel.cs @@ -2,7 +2,6 @@ using System.Text; using System.Text.RegularExpressions; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using JellyBox.Models; using JellyBox.Services; using JellyBox.Views; @@ -469,14 +468,13 @@ private void UpdateUserData() continue; } - cards.Add(CardFactory.CreateFromItem(item, CardShape.Backdrop, ImageType.Thumb, _imageResolver)); + cards.Add(CardFactory.CreateFromItem(item, CardShape.Backdrop, ImageType.Thumb, _imageResolver, _navigationManager)); } return new Section { Name = "Next Up", Cards = cards, - NavigateToCardCommand = NavigateToCardCommand, }; } @@ -562,7 +560,7 @@ private void UpdateUserData() continue; } - cards.Add(CardFactory.CreateFromItem(item, cardShape, ImageType.Thumb, _imageResolver)); + cards.Add(CardFactory.CreateFromItem(item, cardShape, ImageType.Thumb, _imageResolver, _navigationManager)); } // TODO: Support list view for Type == MusicAlbum | Season @@ -570,16 +568,9 @@ private void UpdateUserData() { Name = sectionName, Cards = cards, - NavigateToCardCommand = NavigateToCardCommand, }; } - [RelayCommand] - private void NavigateToCard(Card card) - { - _navigationManager.NavigateToItem(card.Item); - } - private static Uri GetWebVideoUri(string url) { Match match = YouTubeRegex.Match(url); diff --git a/src/JellyBox/ViewModels/MoviesViewModel.cs b/src/JellyBox/ViewModels/MoviesViewModel.cs index 7e694ce..b72cfb5 100644 --- a/src/JellyBox/ViewModels/MoviesViewModel.cs +++ b/src/JellyBox/ViewModels/MoviesViewModel.cs @@ -1,6 +1,5 @@ using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using JellyBox.Models; using JellyBox.Services; using JellyBox.Views; @@ -66,14 +65,8 @@ private async Task InitializeMoviesAsync() continue; } - Movies.Add(CardFactory.CreateFromItem(item, CardShape.Portrait, preferredImageType: null, _imageResolver)); + Movies.Add(CardFactory.CreateFromItem(item, CardShape.Portrait, preferredImageType: null, _imageResolver, _navigationManager)); } } } - - [RelayCommand] - private void NavigateToCard(Card card) - { - _navigationManager.NavigateToItem(card.Item); - } } \ No newline at end of file diff --git a/src/JellyBox/ViewModels/ShowsViewModel.cs b/src/JellyBox/ViewModels/ShowsViewModel.cs index f0027e4..951d631 100644 --- a/src/JellyBox/ViewModels/ShowsViewModel.cs +++ b/src/JellyBox/ViewModels/ShowsViewModel.cs @@ -1,6 +1,5 @@ -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Input; using JellyBox.Models; using JellyBox.Services; using JellyBox.Views; @@ -67,14 +66,8 @@ private async Task InitializeShowsAsync() continue; } - Shows.Add(CardFactory.CreateFromItem(item, CardShape.Portrait, preferredImageType: null, _imageResolver)); + Shows.Add(CardFactory.CreateFromItem(item, CardShape.Portrait, preferredImageType: null, _imageResolver, _navigationManager)); } } } - - [RelayCommand] - private void NavigateToCard(Card card) - { - _navigationManager.NavigateToItem(card.Item); - } } \ No newline at end of file diff --git a/src/JellyBox/Views/ItemDetails.xaml b/src/JellyBox/Views/ItemDetails.xaml index c6ce504..e55693f 100644 --- a/src/JellyBox/Views/ItemDetails.xaml +++ b/src/JellyBox/Views/ItemDetails.xaml @@ -253,7 +253,7 @@ ScrollViewer.VerticalScrollMode="Disabled" SelectionMode="None"> - + diff --git a/src/JellyBox/Views/Movies.xaml b/src/JellyBox/Views/Movies.xaml index 1525aec..9c43cd5 100644 --- a/src/JellyBox/Views/Movies.xaml +++ b/src/JellyBox/Views/Movies.xaml @@ -31,7 +31,7 @@ IsItemClickEnabled="True"> - + diff --git a/src/JellyBox/Views/Shows.xaml b/src/JellyBox/Views/Shows.xaml index be511c3..40a779f 100644 --- a/src/JellyBox/Views/Shows.xaml +++ b/src/JellyBox/Views/Shows.xaml @@ -31,7 +31,7 @@ IsItemClickEnabled="True"> - +