Skip to content

Commit

Permalink
Created detail view for BeatSaver
Browse files Browse the repository at this point in the history
  • Loading branch information
rithik-b committed Mar 21, 2022
1 parent b1bf445 commit 0ea26a0
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 29 deletions.
2 changes: 1 addition & 1 deletion MorePlaylists/BeatSaver/BeatSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public Sprite Logo
public event Action<ViewController, ViewController.AnimationDirection>? ViewControllerRequested;
public event Action<ViewController, ViewController.AnimationDirection, Action?>? ViewControllerDismissRequested;

public BeatSaver(UBinder<Plugin, PluginMetadata> metadata, BeatSaverFiltersViewController filtersViewController, BeatSaverListViewController listViewController, BasicDetailViewController detailViewController)
public BeatSaver(UBinder<Plugin, PluginMetadata> metadata, BeatSaverFiltersViewController filtersViewController, BeatSaverListViewController listViewController, BeatSaverDetailViewController detailViewController)
{
var options = new BeatSaverOptions(metadata.Value.Name, metadata.Value.HVersion.ToString());
beatSaverInstance = new BeatSaverSharp.BeatSaver(options);
Expand Down
22 changes: 22 additions & 0 deletions MorePlaylists/BeatSaver/BeatSaverDetailView.bsml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<vertical horizontal-fit='PreferredSize' vertical-fit='PreferredSize' pref-width='70'>
<horizontal horizontal-fit='PreferredSize' pref-width='60' pref-height="15" spacing="1" bg="panel-top" pad-left="2" child-control-width="false">
<vertical vertical-fit='PreferredSize' pref-width='10' pref-height='10'>
<image id='playlist-cover' preserve-aspect='false' />
</vertical>
<vertical vertical-fit='PreferredSize' pref-width="45" spacing="-1" pref-height="10">
<text text='~playlist-name' text-align="left" word-wrapping='true' />
<horizontal child-control-height="false" child-control-width="false" spacing="0.5">
<image id='user-image' preserve-aspect='true' size-delta-x="3" size-delta-y="3" />
<clickable-text text='~playlist-author' font-size="3.5" font-align="MidlineLeft" word-wrapping='true' color="#FFFFFFBF" size-delta-x="45" size-delta-y="3" />
</horizontal>
</vertical>
</horizontal>
<horizontal horizontal-fit='PreferredSize' vertical-fit='PreferredSize' pref-width='65' pref-height='35' spacing='2'>
<text-page id='text-page' text='~playlist-description' />
</horizontal>
<primary-button text='Go To Playlist!' on-click='go-to-playlist' active='~go-to-active' pref-height='10' pref-width='50' anchor-pos-y='25' />
<horizontal pref-width='60' horizontal-fit='PreferredSize' vertical-fit='PreferredSize' spacing='2' active='~download-active'>
<button text='⏬ Playlist' on-click='download-click' interactable='~download-interactable' pad='0' pref-height='8' pref-width='25' anchor-pos-y='25' />
<button text='⏬ Playlist + Songs' on-click='download-all-click' interactable='~download-interactable' pad='0' pref-height='8' pref-width='35' anchor-pos-y='25' />
</horizontal>
</vertical>
160 changes: 160 additions & 0 deletions MorePlaylists/BeatSaver/BeatSaverDetailViewController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using System;
using System.Threading;
using BeatSaberMarkupLanguage.Attributes;
using BeatSaberMarkupLanguage.ViewControllers;
using BeatSaberPlaylistsLib.Types;
using HMUI;
using MorePlaylists.Entries;
using MorePlaylists.UI;
using MorePlaylists.Utilities;
using UnityEngine;
using Zenject;

namespace MorePlaylists.BeatSaver;

[HotReload(RelativePathToLayout = @".\BeatSaverDetailView.bsml")]
[ViewDefinition("MorePlaylists.BeatSaver.BeatSaverDetailView.bsml")]
internal class BeatSaverDetailViewController : BSMLAutomaticViewController, IDetailViewController
{
[Inject]
private readonly SpriteLoader spriteLoader = null!;

[Inject]
private readonly MaterialGrabber materialGrabber = null!;

private BeatSaverEntry? selectedPlaylistEntry;
private CancellationTokenSource? spriteLoadTokenSource;

public ViewController ViewController => this;
public event Action<IEntry, bool>? DidPressDownload;
public event Action<IPlaylist>? DidGoToPlaylist;

[UIComponent("playlist-cover")]
private readonly ImageView playlistCoverView = null!;

[UIComponent("user-image")]
private readonly ImageView userImageView = null!;

[UIComponent("text-page")]
private readonly TextPageScrollView descriptionTextPage = null!;

#region Actions

[UIAction("#post-parse")]
private void PostParse()
{
rectTransform.anchorMax = new Vector2(0.5f, 1);
playlistCoverView.material = materialGrabber.NoGlowRoundEdge;
userImageView.material = materialGrabber.NoGlowRoundEdge;
}

[UIAction("download-click")]
private void DownloadPressed()
{
if (selectedPlaylistEntry != null)
{
DidPressDownload?.Invoke(selectedPlaylistEntry, false);
NotifyPropertyChanged(nameof(DownloadInteractable));
}
}

[UIAction("download-all-click")]
private void DownloadAllPressed()
{
if (selectedPlaylistEntry != null)
{
DidPressDownload?.Invoke(selectedPlaylistEntry, true);
NotifyPropertyChanged(nameof(DownloadInteractable));
}
}

[UIAction("go-to-playlist")]
private void GoToPlaylist()
{
if (selectedPlaylistEntry?.LocalPlaylist != null)
{
DidGoToPlaylist?.Invoke(selectedPlaylistEntry.LocalPlaylist);
}
}

#endregion

public void ShowDetail(IEntry selectedPlaylistEntry)
{
if (selectedPlaylistEntry is BeatSaverEntry beatSaverEntry)
{
this.selectedPlaylistEntry = beatSaverEntry;
NotifyPropertyChanged(nameof(DownloadInteractable));
NotifyPropertyChanged(nameof(DownloadActive));
NotifyPropertyChanged(nameof(GoToActive));
NotifyPropertyChanged(nameof(PlaylistName));
NotifyPropertyChanged(nameof(PlaylistAuthor));
NotifyPropertyChanged(nameof(PlaylistDescription));
descriptionTextPage.ScrollTo(0, true);

spriteLoadTokenSource?.Cancel();
spriteLoadTokenSource?.Dispose();
spriteLoadTokenSource = new CancellationTokenSource();
_ = spriteLoader.DownloadSpriteAsync(beatSaverEntry.SpriteURL, sprite => playlistCoverView.sprite = sprite, spriteLoadTokenSource.Token);
userImageView.sprite = BeatSaberMarkupLanguage.Utilities.ImageResources.BlankSprite;
_ = spriteLoader.DownloadSpriteAsync(beatSaverEntry.Owner.Avatar, sprite => userImageView.sprite = sprite, spriteLoadTokenSource.Token);
}
}

public void OnPlaylistDownloaded()
{
NotifyPropertyChanged(nameof(DownloadInteractable));
NotifyPropertyChanged(nameof(DownloadActive));
NotifyPropertyChanged(nameof(GoToActive));
}

#region Values

[UIValue("playlist-name")]
public string PlaylistName
{
get
{
if (selectedPlaylistEntry != null)
{
if (selectedPlaylistEntry.Title.Length > 32)
{
return selectedPlaylistEntry.Title.Substring(0, 28) + "...";
}
return selectedPlaylistEntry.Title;
}
return string.Empty;
}
}

[UIValue("playlist-author")]
public string PlaylistAuthor
{
get
{
if (selectedPlaylistEntry != null)
{
if (selectedPlaylistEntry.Author.Length > 32)
{
return selectedPlaylistEntry.Author.Substring(0, 28) + "...";
}
return selectedPlaylistEntry.Author;
}
return string.Empty;
}
}

[UIValue("playlist-description")]
private string PlaylistDescription => string.IsNullOrWhiteSpace(selectedPlaylistEntry?.Description) ? "No Description available for this playlist." : selectedPlaylistEntry?.Description ?? "";

[UIValue("download-interactable")]
public bool DownloadInteractable => selectedPlaylistEntry is {DownloadBlocked: false};

[UIValue("download-active")]
public bool DownloadActive => selectedPlaylistEntry is {LocalPlaylist: null};

[UIValue("go-to-active")]
public bool GoToActive => selectedPlaylistEntry is {LocalPlaylist: { }};

#endregion
}
3 changes: 3 additions & 0 deletions MorePlaylists/BeatSaver/BeatSaverEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading;
using System.Threading.Tasks;
using BeatSaberPlaylistsLib.Types;
using BeatSaverSharp.Models;
using BeatSaverSharp.Models.Pages;
using MorePlaylists.Entries;
using SiraUtil.Web;
Expand All @@ -27,6 +28,8 @@ public BeatSaverEntry(Playlist playlist)
public string SpriteURL => playlist.CoverURL;
public IPlaylist? LocalPlaylist { get; set; }
public bool DownloadBlocked { get; set; }
public User Owner => playlist.Owner;


public async Task<List<Song>?> GetSongs(IHttpService siraHttpService, CancellationToken cancellationToken = default)
{
Expand Down
2 changes: 1 addition & 1 deletion MorePlaylists/BeatSaver/BeatSaverListViewController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void SetEntryAsOwned(IEntry playlistEntry)
if (index >= 0 && customListTableData != null)
{
customListTableData.data[index] = new CustomListTableData.CustomCellInfo($"<#7F7F7F>{playlistEntry.Title}", playlistEntry.Author);
spriteLoader.GetSpriteForEntry(playlistEntry, sprite =>
_ = spriteLoader.DownloadSpriteAsync(playlistEntry.SpriteURL, sprite =>
{
customListTableData.data[index].icon = sprite;
customListTableData.tableView.ReloadDataKeepingPosition();
Expand Down
3 changes: 2 additions & 1 deletion MorePlaylists/Installers/MorePlaylistsMenuInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public override void InstallBindings()
{
Container.BindInterfacesTo<BeatSaver.BeatSaver>().AsSingle();
Container.BindInterfacesAndSelfTo<BeatSaverListViewController>().FromNewComponentAsViewController().AsSingle();
Container.BindInterfacesAndSelfTo<BeatSaverDetailViewController>().FromNewComponentAsViewController().AsSingle();
Container.BindInterfacesAndSelfTo<BeatSaverFiltersViewController>().FromNewComponentAsViewController().AsSingle();


Container.BindInterfacesTo<Hitbloq.Hitbloq>().AsSingle();
Container.BindInterfacesTo<AccSaber.AccSaber>().AsSingle();
Expand All @@ -31,6 +31,7 @@ public override void InstallBindings()

Container.Bind<SpriteLoader>().AsSingle();
Container.Bind<InputFieldGrabber>().AsSingle();
Container.Bind<MaterialGrabber>().AsSingle();
}
}
}
1 change: 1 addition & 0 deletions MorePlaylists/MorePlaylists.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="BeatSaver\BeatSaverDetailView.bsml" />
<EmbeddedResource Include="BeatSaver\BeatSaverFiltersView.bsml" />
<EmbeddedResource Include="manifest.json" />
<EmbeddedResource Include="Images\*.png" />
Expand Down
9 changes: 7 additions & 2 deletions MorePlaylists/UI/ViewControllers/BasicDetailViewController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using MorePlaylists.Utilities;
using System;
using System.Linq;
using System.Threading;
using BeatSaberPlaylistsLib.Types;
using UnityEngine;
using Zenject;
Expand All @@ -18,7 +19,11 @@ internal class BasicDetailViewController : BSMLAutomaticViewController, IDetailV
[Inject]
private readonly SpriteLoader spriteLoader = null!;

[Inject]
private readonly MaterialGrabber materialGrabber = null!;

private IEntry? selectedPlaylistEntry;

public ViewController ViewController => this;
public event Action<IEntry, bool>? DidPressDownload;
public event Action<IPlaylist>? DidGoToPlaylist;
Expand All @@ -35,7 +40,7 @@ internal class BasicDetailViewController : BSMLAutomaticViewController, IDetailV
private void PostParse()
{
rectTransform.anchorMax = new Vector2(0.5f, 1);
playlistCoverView.material = Resources.FindObjectsOfTypeAll<Material>().First(m => m.name == "UINoGlowRoundEdge");
playlistCoverView.material = materialGrabber.NoGlowRoundEdge;
}

[UIAction("download-click")]
Expand Down Expand Up @@ -78,8 +83,8 @@ public void ShowDetail(IEntry selectedPlaylistEntry)
NotifyPropertyChanged(nameof(PlaylistName));
NotifyPropertyChanged(nameof(PlaylistAuthor));
NotifyPropertyChanged(nameof(PlaylistDescription));
spriteLoader.GetSpriteForEntry(selectedPlaylistEntry, sprite => playlistCoverView.sprite = sprite);
descriptionTextPage.ScrollTo(0, true);
_ = spriteLoader.DownloadSpriteAsync(selectedPlaylistEntry.SpriteURL, sprite => playlistCoverView.sprite = sprite);
}

public void OnPlaylistDownloaded()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void SetEntryAsOwned(IEntry playlistEntry)
if (index >= 0 && customListTableData != null)
{
customListTableData.data[index] = new CustomListTableData.CustomCellInfo($"<#7F7F7F>{playlistEntry.Title}", playlistEntry.Author);
spriteLoader.GetSpriteForEntry(playlistEntry, sprite =>
_ = spriteLoader.DownloadSpriteAsync(playlistEntry.SpriteURL, sprite =>
{
customListTableData.data[index].icon = sprite;
customListTableData.tableView.ReloadDataKeepingPosition();
Expand Down
40 changes: 19 additions & 21 deletions MorePlaylists/UI/Views/BasicDetailView.bsml
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
<div>
<vertical horizontal-fit='PreferredSize' vertical-fit='PreferredSize' pref-width='70'>
<horizontal horizontal-fit='PreferredSize' pref-width='60' pref-height="15" bg="panel-top">
<vertical vertical-fit='PreferredSize' pref-width='10' pref-height='10'>
<image id='playlist-cover' preserve-aspect='false' />
</vertical>
<vertical vertical-fit='PreferredSize' pref-width="45" spacing="-1" pref-height="10">
<text text='~playlist-name' text-align="left" word-wrapping='true' />
<text text='~playlist-author' text-align="left" word-wrapping='true' color="#FFFFFFBF" />
</vertical>
</horizontal>
<horizontal horizontal-fit='PreferredSize' vertical-fit='PreferredSize' pref-width='65' pref-height='35' spacing='2'>
<text-page id='text-page' text='~playlist-description' />
</horizontal>
<primary-button text='Go To Playlist!' on-click='go-to-playlist' active='~go-to-active' pref-height='10' pref-width='50' anchor-pos-y='25' />
<horizontal pref-width='60' horizontal-fit='PreferredSize' vertical-fit='PreferredSize' spacing='2' active='~download-active'>
<button text='⏬ Playlist' on-click='download-click' interactable='~download-interactable' pad='0' pref-height='8' pref-width='25' anchor-pos-y='25' />
<button text='⏬ Playlist + Songs' on-click='download-all-click' interactable='~download-interactable' pad='0' pref-height='8' pref-width='35' anchor-pos-y='25' />
</horizontal>
</vertical>
</div>
<vertical horizontal-fit='PreferredSize' vertical-fit='PreferredSize' pref-width='70'>
<horizontal horizontal-fit='PreferredSize' pref-width='60' pref-height="15" bg="panel-top" pad-left="2" child-control-width="false">
<vertical vertical-fit='PreferredSize' pref-width='10' pref-height='10'>
<image id='playlist-cover' preserve-aspect='false' />
</vertical>
<vertical vertical-fit='PreferredSize' pref-width="45" spacing="-1" pref-height="10">
<text text='~playlist-name' text-align="left" word-wrapping='true' />
<text text='~playlist-author' text-align="left" word-wrapping='true' color="#FFFFFFBF" />
</vertical>
</horizontal>
<horizontal horizontal-fit='PreferredSize' vertical-fit='PreferredSize' pref-width='65' pref-height='35' spacing='2'>
<text-page id='text-page' text='~playlist-description' />
</horizontal>
<primary-button text='Go To Playlist!' on-click='go-to-playlist' active='~go-to-active' pref-height='10' pref-width='50' anchor-pos-y='25' />
<horizontal pref-width='60' horizontal-fit='PreferredSize' vertical-fit='PreferredSize' spacing='2' active='~download-active'>
<button text='⏬ Playlist' on-click='download-click' interactable='~download-interactable' pad='0' pref-height='8' pref-width='25' anchor-pos-y='25' />
<button text='⏬ Playlist + Songs' on-click='download-all-click' interactable='~download-interactable' pad='0' pref-height='8' pref-width='35' anchor-pos-y='25' />
</horizontal>
</vertical>
10 changes: 10 additions & 0 deletions MorePlaylists/Utilities/MaterialGrabber.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Linq;
using UnityEngine;

namespace MorePlaylists.Utilities;

public class MaterialGrabber
{
private Material? noGlowRoundEdge;
public Material NoGlowRoundEdge => noGlowRoundEdge ??= Resources.FindObjectsOfTypeAll<Material>().First(m => m.name == "UINoGlowRoundEdge");
}
2 changes: 0 additions & 2 deletions MorePlaylists/Utilities/SpriteLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ public SpriteLoader(IHttpService siraHttpService)
spriteQueue = new ConcurrentQueue<Action>();
}

public void GetSpriteForEntry(IEntry entry, Action<Sprite> onCompletion) => _ = DownloadSpriteAsync(entry.SpriteURL, onCompletion);

public async Task DownloadSpriteAsync(string spriteURL, Action<Sprite> onCompletion, CancellationToken cancellationToken = default)
{
// Check Cache
Expand Down

0 comments on commit 0ea26a0

Please sign in to comment.