Skip to content

Commit

Permalink
implement mix playlist with options
Browse files Browse the repository at this point in the history
  • Loading branch information
zznty committed Oct 12, 2024
1 parent 9af2f86 commit bbdc75b
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 72 deletions.
30 changes: 0 additions & 30 deletions MusicX.Core/Models/Mix/MixOption.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Newtonsoft.Json;
using System.IO.Compression;
using System.Text.Json.Nodes;

namespace MusicX.Core.Models.Mix
{
Expand All @@ -18,33 +16,5 @@ public class MixOption

[JsonProperty("selected")]
public bool Selected { get; set; }

[Newtonsoft.Json.JsonIgnore]
public byte[] ImageBytes
{
get
{
using(var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");

var response = httpClient.GetAsync(IconUri).GetAwaiter().GetResult();

using var stream = response.Content.ReadAsStreamAsync().GetAwaiter().GetResult();
using var decompressedStream = new GZipStream(stream, CompressionMode.Decompress);
using var reader = new StreamReader(decompressedStream);
var lottieJson = reader.ReadToEndAsync().GetAwaiter().GetResult();


var jsonOnject = JsonObject.Parse(lottieJson);

var base64Image = jsonOnject["assets"][0]["p"].AsValue().ToString();

var imageBytes = Convert.FromBase64String(base64Image.Replace("data:image/png;base64,", string.Empty));

return imageBytes;
}
}
}
}
}
45 changes: 43 additions & 2 deletions MusicX/Controls/Blocks/AudioMixesBlock.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@
using MusicX.ViewModels.Modals;
using MusicX.Views.Modals;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Wpf.Ui.Common;

namespace MusicX.Controls.Blocks;

Expand All @@ -33,6 +38,7 @@ public bool IsPlaying
public static readonly DependencyProperty IsPlayingProperty =
DependencyProperty.Register("IsPlaying", typeof(bool), typeof(AudioMixesBlock));
private readonly PlayerService _player;
private ImmutableDictionary<string, ImmutableArray<string>>? _options;

public AudioMixesBlock()
{
Expand Down Expand Up @@ -66,9 +72,14 @@ private async void Button_Click(object sender, RoutedEventArgs e)
return;
}

var data = new MixOptions("common");
await PlayPlaylist();
}

private Task PlayPlaylist()
{
var data = new MixOptions("common", Options: _options);

await _player.PlayAsync(new MixPlaylist(data, StaticService.Container.GetRequiredService<VkService>()));
return _player.PlayAsync(new MixPlaylist(data, StaticService.Container.GetRequiredService<VkService>()));
}

private void LibraryButton_Click(object sender, RoutedEventArgs e)
Expand All @@ -94,8 +105,38 @@ private async void MixSettings_Click(object sender, RoutedEventArgs e)
var navigationService = StaticService.Container.GetRequiredService<NavigationService>();
var vm = StaticService.Container.GetRequiredService<MixSettingsModalViewModel>();

vm.ApplyCommand = new RelayCommand(() =>
{
SetOptions(vm.Categories);
navigationService.CloseModal();
});
vm.ResetCommand = new RelayCommand(() =>
{
_options = null;
navigationService.CloseModal();
});

await vm.LoadSettings("common");

navigationService.OpenModal<MixSettingsModal>(vm);
}

private async void SetOptions(IEnumerable<MixSettingsCategoryViewModel> categories)
{
var builder = ImmutableDictionary<string, ImmutableArray<string>>.Empty.ToBuilder();

foreach (var category in categories)
{
foreach (var option in category.Options.Where(b => b.Selected))
{
builder[category.Id] = builder.TryGetValue(category.Id, out var value)
? value.Add(option.Id)
: [option.Id];
}
}

_options = builder.Count == 0 ? null : builder.ToImmutable();

await PlayPlaylist();
}
}
107 changes: 75 additions & 32 deletions MusicX/ViewModels/Modals/MixSettingsModalViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,94 @@
using MusicX.Core.Models.Mix;
using System;
using MusicX.Core.Models.Mix;
using MusicX.Core.Services;
using System.Collections.ObjectModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows.Input;
using AsyncAwaitBestPractices;
using Wpf.Ui.Common;

namespace MusicX.ViewModels.Modals
{
public class MixSettingsModalViewModel : BaseViewModel
{

public string Title { get; set; }
namespace MusicX.ViewModels.Modals;

public string Subtitle { get; set; }
public class MixSettingsModalViewModel(VkService vkService) : BaseViewModel
{
public string Title { get; set; } = string.Empty;

public bool IsLoading { get; set; }
public string Subtitle { get; set; } = string.Empty;

public bool IsLoading { get; set; }

public ObservableCollection<MixSettingsCategoryViewModel> Categories { get; set; } = [];

public ICommand? ApplyCommand { get; set; }
public ICommand? ResetCommand { get; set; }

public ObservableCollection<MixCategory> Categories { get; set; }
public async Task LoadSettings(string mixId)
{
IsLoading = true;

var settings = await vkService.GetStreamMixSettings(mixId);

private readonly VkService _vkService;
IsLoading = false;
Title = settings.Settings.Title;
Subtitle = settings.Settings.Subtitle;
Categories = new(settings.Settings.Categories.Select(b => new MixSettingsCategoryViewModel(b)));
}
}

public MixSettingsModalViewModel(VkService vkService)
{
_vkService = vkService;
}
public class MixSettingsCategoryViewModel : BaseViewModel
{
public string Title { get; set; }
public string Id { get; set; }
public string Type { get; set; }
public ObservableCollection<MixSettingsOptionViewModel> Options { get; set; }

public MixSettingsCategoryViewModel(MixCategory category)
{
Title = category.Title;
Id = category.Id;
Type = category.Type;
Options = new(category.Options.Select(o => new MixSettingsOptionViewModel(o)));
}
}

public class MixSettingsOptionViewModel : BaseViewModel
{
public string Title { get; set; }
public string Id { get; set; }

public byte[]? Icon { get; set; }

public bool Selected { get; set; }

public MixSettingsOptionViewModel(MixOption option)
{
Title = option.Title;
Id = option.Id;
if (!string.IsNullOrEmpty(option.IconUri))
Load(option.IconUri).SafeFireAndForget();
}

public async Task LoadSettings(string mixId)
private async Task Load(string uri)
{
using var httpClient = new HttpClient(new HttpClientHandler
{
IsLoading = true;
OnPropertyChanged(nameof(IsLoading));

var settings = await _vkService.GetStreamMixSettings(mixId);

IsLoading = false;
OnPropertyChanged(nameof(IsLoading));
AutomaticDecompression = DecompressionMethods.All
});

await using var stream = await httpClient.GetStreamAsync(uri);

this.Title = settings.Settings.Title;
OnPropertyChanged(nameof(Title));
var jsonObject = await JsonNode.ParseAsync(stream);

if (jsonObject is null) return;

this.Subtitle = settings.Settings.Subtitle;
OnPropertyChanged(nameof(Subtitle));
var base64Image = jsonObject["assets"]![0]!["p"]!.AsValue().ToString();

this.Categories = new ObservableCollection<MixCategory>(settings.Settings.Categories);
OnPropertyChanged(nameof(Subtitle));

}
Icon = Convert.FromBase64String(base64Image["data:image/png;base64,".Length..]);
}
}
}
20 changes: 12 additions & 8 deletions MusicX/Views/Modals/MixSettingsModal.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MusicX.Views.Modals"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
xmlns:modals="clr-namespace:MusicX.ViewModels.Modals"
mc:Ignorable="d"
MinWidth="400"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance modals:MixSettingsModalViewModel}"
Title="{Binding Title}">

<Grid>
Expand All @@ -33,11 +35,11 @@
<DataTrigger Binding="{Binding Type}" Value="pictured_button_horizontal_group">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<DataTemplate DataType="{x:Type modals:MixSettingsOptionViewModel}">
<StackPanel Margin="0,5,5,5">
<ToggleButton Width="100" Height="100">
<ToggleButton Width="100" Height="100" IsChecked="{Binding Selected}">
<StackPanel HorizontalAlignment="Center">
<Image Height="50" Width="50" Source="{Binding ImageBytes}"/>
<Image Height="50" Width="50" Source="{Binding Icon}"/>
<TextBlock Margin="0,5,0,0" HorizontalAlignment="Center" TextAlignment="Center" VerticalAlignment="Center" Width="120" Text="{Binding Title}"/>
</StackPanel>
</ToggleButton>
Expand All @@ -50,9 +52,9 @@
<DataTrigger Binding="{Binding Type}" Value="button_horizontal_group">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<DataTemplate DataType="{x:Type modals:MixSettingsOptionViewModel}">
<Grid Margin="0,5,5,5">
<ToggleButton Width="120" Content="{Binding Title}"/>
<ToggleButton Width="120" IsChecked="{Binding Selected}" Content="{Binding Title}"/>
</Grid>
</DataTemplate>
</Setter.Value>
Expand All @@ -73,8 +75,10 @@
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

<ui:Button HorizontalAlignment="Stretch" Margin="5,0,0,0" Appearance="Secondary" Grid.Column="1" Content="Применить"/>
<ui:Button HorizontalAlignment="Stretch" Appearance="Transparent" Grid.Column="0" Content="Сбросить"/>
<ui:Button HorizontalAlignment="Stretch" Margin="5,0,0,0" Appearance="Secondary" Grid.Column="1"
Content="Применить" Command="{Binding ApplyCommand}" />
<ui:Button HorizontalAlignment="Stretch" Appearance="Transparent" Grid.Column="0" Content="Сбросить"
Command="{Binding ResetCommand}" />
</Grid>
</StackPanel>

Expand Down

0 comments on commit bbdc75b

Please sign in to comment.