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
27 changes: 8 additions & 19 deletions src/JellyBox/Behaviors/ListViewBaseCommandBehavior.cs
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// 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.
/// </summary>
internal sealed class ListViewBaseCommandBehavior : Behavior<ListViewBase>
{
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();
Expand All @@ -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);
}
}
}
}
8 changes: 4 additions & 4 deletions src/JellyBox/Models/Card.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Windows.Input;
using JellyBox.Services;
using Jellyfin.Sdk.Generated.Models;

namespace JellyBox.Models;

Expand All @@ -11,15 +11,15 @@ 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; }

public required int ImageHeight { get; init; }

public required JellyfinImage Image { get; init; }

public required ICommand NavigateCommand { get; init; }
}
6 changes: 4 additions & 2 deletions src/JellyBox/Models/CardFactory.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using CommunityToolkit.Mvvm.Input;
using JellyBox.Services;
using Jellyfin.Sdk.Generated.Models;

Expand All @@ -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;
Expand Down Expand Up @@ -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)),
};
}

Expand Down
11 changes: 11 additions & 0 deletions src/JellyBox/Models/INavigable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Windows.Input;

namespace JellyBox.Models;

/// <summary>
/// Interface for UI models that support navigation when activated.
/// </summary>
internal interface INavigable
{
ICommand NavigateCommand { get; }
}
4 changes: 0 additions & 4 deletions src/JellyBox/Models/Section.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
using System.Windows.Input;

namespace JellyBox.Models;

internal sealed class Section
{
public required string Name { get; set; }

public required IReadOnlyList<Card>? Cards { get; set; }

public required ICommand NavigateToCardCommand { get; set; }
}
2 changes: 1 addition & 1 deletion src/JellyBox/Resources/Templates.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
ScrollViewer.VerticalScrollMode="Disabled"
SelectionMode="None">
<Interactivity:Interaction.Behaviors>
<Behaviors:ListViewBaseCommandBehavior Command="{x:Bind NavigateToCardCommand}" />
<Behaviors:ListViewBaseCommandBehavior />
</Interactivity:Interaction.Behaviors>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
Expand Down
10 changes: 1 addition & 9 deletions src/JellyBox/ViewModels/HomeViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
}
}
13 changes: 2 additions & 11 deletions src/JellyBox/ViewModels/ItemDetailsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
};
}

Expand Down Expand Up @@ -562,24 +560,17 @@ 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
return new Section
{
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);
Expand Down
9 changes: 1 addition & 8 deletions src/JellyBox/ViewModels/MoviesViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
}
}
11 changes: 2 additions & 9 deletions src/JellyBox/ViewModels/ShowsViewModel.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
}
}
2 changes: 1 addition & 1 deletion src/JellyBox/Views/ItemDetails.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@
ScrollViewer.VerticalScrollMode="Disabled"
SelectionMode="None">
<Interactivity:Interaction.Behaviors>
<Behaviors:ListViewBaseCommandBehavior Command="{x:Bind Path=NavigateToCardCommand}" />
<Behaviors:ListViewBaseCommandBehavior />
</Interactivity:Interaction.Behaviors>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
Expand Down
2 changes: 1 addition & 1 deletion src/JellyBox/Views/Movies.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
IsItemClickEnabled="True">
<Interactivity:Interaction.Behaviors>
<Behaviors:FocusFirstItemOnLoadBehavior />
<Behaviors:ListViewBaseCommandBehavior Command="{x:Bind ViewModel.NavigateToCardCommand}" />
<Behaviors:ListViewBaseCommandBehavior />
</Interactivity:Interaction.Behaviors>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
Expand Down
2 changes: 1 addition & 1 deletion src/JellyBox/Views/Shows.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
IsItemClickEnabled="True">
<Interactivity:Interaction.Behaviors>
<Behaviors:FocusFirstItemOnLoadBehavior />
<Behaviors:ListViewBaseCommandBehavior Command="{x:Bind ViewModel.NavigateToCardCommand}" />
<Behaviors:ListViewBaseCommandBehavior />
</Interactivity:Interaction.Behaviors>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
Expand Down